首页 > 其他分享 >题解 P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并

题解 P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并

时间:2023-06-07 14:47:43浏览次数:60  
标签:return int 题解 res leq num P4556 Vani 救济粮

传送门

如题目所言,这就是个线段树合并的板子题。

题目大意

题目描述

首先村落里的一共有 \(n\) 座房屋,并形成一个树状结构。然后救济粮分 \(m\) 次发放,每次选择两个房屋 \((x, y)\),然后对于 \(x\) 到 \(y\) 的路径上(含 \(x\) 和 \(y\))每座房子里发放一袋 \(z\) 类型的救济粮。

然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。

输入格式

输入的第一行是两个用空格隔开的正整数,分别代表房屋的个数 \(n\) 和救济粮发放的次数 \(m\)。

第 \(2\) 到 第 \(n\) 行,每行有两个用空格隔开的整数 \(a, b\),代表存在一条连接房屋 \(a\) 和 \(b\) 的边。

第 \((n + 1)\) 到第 \((n + m)\) 行,每行有三个用空格隔开的整数 \(x, y, z\),代表一次救济粮的发放是从 \(x\) 到 \(y\) 路径上的每栋房子发放了一袋 \(z\) 类型的救济粮。

输出格式

输出 \(n\) 行,每行一个整数,第 \(i\) 行的整数代表 \(i\) 号房屋存放最多的救济粮的种类,如果有多种救济粮都是存放最多的,输出种类编号最小的一种。

如果某座房屋没有救济粮,则输出 \(0\)。

样例输入

5 3
1 2
3 1
3 4
5 3
2 3 3
1 5 2
3 3 3

样例输出

2
3
3
0
2

数据范围

对于 \(20\%\) 的数据,保证 \(n, m \leq 100\)。
对于 \(50\%\) 的数据,保证 \(n, m \leq 2 \times 10^3\)。
对于 \(100\%\) 测试数据,保证 \(1 \leq n, m \leq 10^5\),\(1 \leq a,b,x,y \leq n\),\(1 \leq z \leq 10^5\)。

大概思路

先建好图,再跑树剖(求lca),用树上点差分表示每个点上的物品的个数,再把每个点当成一个线段树进行线段树合并,将子节点合并到父节点上,求出每个点上最多的物品种类即可。
本题 \(z\) 的数据范围不是很大,如果过大则需要离散化。

AC代码

#include <bits/stdc++.h>
using namespace std;

const int maxn(100005);

inline int read() {
    int f(1), x(0);
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for (; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c & 15);
    return f * x;
}

int n, m, a, b, c;
int head[maxn], nxt[maxn << 1], ver[maxn << 1], tot;
int hson[maxn], dep[maxn], fa[maxn], siz[maxn];
int dfn[maxn], rdfn[maxn], cnt, top[maxn];
int d[maxn]; // 可以理解为差分数组,但更好地理解是,d[]是一棵棵线段树
int ans[maxn];

inline void add(int x, int y) {
    ver[++tot] = y, nxt[tot] = head[x], head[x] = tot;
}

void dfs1(int x) {
    hson[x] = -1; siz[x] = 1;

    for (int i = head[x]; ~i; i = nxt[i]) {
        int y = ver[i];
        if (dep[y]) continue;

        fa[y] = x;
        dep[y] = dep[x] + 1;
        dfs1(y);

        siz[x] += siz[y];
        if (hson[x] == -1 || siz[y] > siz[hson[x]]) hson[x] = y;
    }
}

void dfs2(int x, int f) {
    top[x] = f;
    dfn[x] = ++cnt; rdfn[cnt] = x;

    if (hson[x] == -1) return;
    dfs2(hson[x], f);

    for (int i = head[x]; ~i; i = nxt[i]) {
        int y = ver[i];
        if (y != fa[x] && y != hson[x]) dfs2(y, y);
    }
}

int lca(int x, int y) {
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]]) {
            swap(x, y);
        }

        x = fa[top[x]];
    }

    if (dep[x] > dep[y]) swap(x, y);
    return x;
};

int cnt1;
struct SegmentTree {
    int l, r, res, num;
    // res 是种类,num 是物品个数
} t[maxn << 6]; // 权值线段树,这里开64倍

void pushup(int p) {
    if (t[t[p].l].num >= t[t[p].r].num) {
        t[p].num = t[t[p].l].num;
        t[p].res = t[t[p].l].res;
    } else {
        t[p].num = t[t[p].r].num;
        t[p].res = t[t[p].r].res;
    }
}

int merge(int a, int b, int l, int r) {
    if (!a) return b;
    if (!b) return a;
    if (l == r) {
        t[a].num += t[b].num;
        return a;
    }

    int mid = (l + r) >> 1;
    t[a].l = merge(t[a].l, t[b].l, l, mid);
    t[a].r = merge(t[a].r, t[b].r, mid + 1, r);

    pushup(a);
    return a;
}

int insert(int p, int l, int r, int x, int v) {
    if (!p) p = ++cnt1;
    if (l == r) {
        t[p].num += v;
        t[p].res = x;
        return p;
    }

    int mid = (l + r) >> 1;
    if (x <= mid) t[p].l = insert(t[p].l, l, mid, x, v);
    else t[p].r = insert(t[p].r, mid + 1, r, x, v);

    pushup(p);
    return p;
}

void redfs(int x) {
    for (int i = head[x]; ~i; i = nxt[i]) {
        int y = ver[i];
        if (dep[y] <= dep[x]) continue;

        redfs(y);
        d[x] = merge(d[x], d[y], 1, 100000);
    }

    if (t[d[x]].num) ans[x] = t[d[x]].res;
}

int main() {
    memset(head, 0xff, sizeof(head));
    dep[1] = 1;

    n = read(), m = read();

    for (int i = 1; i < n; ++i) {
        a = read(), b = read();
        add(a, b); add(b, a);
    }

    dfs1(1), dfs2(1, 1);

    for (int i = 1; i <= m; ++i) {
        a = read(); b = read(), c = read();

        d[a] = insert(d[a], 1, 100000, c, 1);
        d[b] = insert(d[b], 1, 100000, c, 1);
        int t = lca(a, b);
        d[t] = insert(d[t], 1, 100000, c, -1);
        if (fa[t]) d[fa[t]] = insert(d[fa[t]], 1, 100000, c, -1);
    }

    redfs(1);

    for (int i = 1; i <= n; ++i) {
        printf("%d\n", ans[i]);
    }
}

标签:return,int,题解,res,leq,num,P4556,Vani,救济粮
From: https://www.cnblogs.com/Chronologika/p/17463230.html

相关文章

  • 【每日一题】LeetCode 786. 第K个最小的素数分数(待补全题解思路)
    题目给你一个按递增顺序排序的数组arr和一个整数k。数组arr由1和若干素数组成,且其中所有整数互不相同。对于每对满足0<i<j<arr.length的i和j,可以得到分数arr[i]/arr[j]。那么第k个最小的分数是多少呢?以长度为2的整数数组返回你的答案,这里answer......
  • Luogu P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并
    [Vani有约会]雨天的尾巴/【模板】线段树合并题目背景深绘里一直很讨厌雨天。灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。无奈......
  • 2023上半年(下午)网络工程师试题解析
    2023上半年(下午)网络工程师试题解析试题一(20分)某企业办公楼网络拓扑如图1-1所示。该网络中交换机Switch1-Switch4均是二层设备,分布在办公楼的各层,上联采用千兆光纤。核心交换机、防火墙、服务器部署在数据机房,其中核心交换机实现冗余配置。图1-1问题1(4分)该企业办公网络采用172.16.1......
  • CF1559D2 Mocha and Diana (Hard Version) 题解
    Luogu|Codeforces题意给定两个森林\(A\)和\(B\),均有编号\(1\)到\(n\)的节点,边数分别为\(m_1,m_2\)。现在进行加边操作,但是有两个要求:如果在第一个森林加一条\((u,v)\)的边,第二个森林也要进行同样的操作。反之同理。加边后两个森林依旧是森林。一棵树也是森林。......
  • 应用问题解决-分布式锁(LUA保证删除原子性)
    问题:删除操作缺乏原子性场景1、index1获得锁、执行具体操作、比较lock的uuid值确实和自己生成的uuid是否相等,相等则删除锁。uuid=v1set(lock,uuid)uuid.equals(get("lock"))2、但是index1执行删除前,lock刚好过期时间已经到了,被redis自动释放3、此时index2获取锁,执行具体......
  • 在centos7升级nodejs存在的无法切换版本的问题解决
    1.安装n管理工具npminstall-gn安装最新版本nlatest安装指定版本 n8.11.3 2.切换nodejs版本n选择已安装的版本 ο node/8.11.3  node/10.4.1查看当前版本node-v,下面表示已切换成功v8.13.3但问题来了,切换后,查看版本还是原来的v6.13.3,看下面 使用n切换nodejs......
  • 应用问题解决——缓存穿透、缓存击穿、缓存雪崩
    一、缓存穿透缓存穿透:key对应的数据在数据源并不存在,每次针对key的请求从缓存中获取不到,请求都会压到数据源,从而可能压垮数据源,比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库现象:1、应用服务器压力变大2、redis命中率......
  • Meteors 题解
    Meteors蒟蒻初学整体二分,写一篇题解记录一下思考与看法。题目大意在一个环形的轨道上分别着若干国家的空间站,在接下来的一段时间内会出现若干次陨石,每次出现在环形的某一段轨道,每个国家都想收集一定量的陨石,需要判断每个国家最少在什么时候可以集齐所需的陨石。思路分析首先......
  • Full Tank 题解
    FullTank题目大意给定一张\(n\)个点,\(m\)条边的连通无向图,在每个点有一个加油站,油价为该点的点权,每条边的油耗为该边的边权。现给出若干询问,问一辆油箱容量为\(c\)的车子是否能从\(s\)开到\(e\),如果可以,求出最小所需的钱。思路分析看到这种有图有权求最小消耗的题,我......
  • Visible Lattice Points 题解
    VisibleLatticePoints题目大意给定一个\(N×N×N\)的由若干点组成的立方体,点的坐标从\((0,0,0)\)到\((N,N,N)\),求从点\((0,0,0)\)处可以看见多少个点。思路分析我们将立方体上的点分成三类:在\(xy,yz,xz\)平面上的点。在\(x,y,z\)轴上的点。即不在平面,也不在......