码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj5457 城市

时间:2019-03-12 12:04:59      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:alt   维护   \n   main   城市   c++   需要   div   log   

一棵树,每个点有一个民族,和一个人数,求每个子树里最多的民族及其人数,如果一样,输出编号最小的

$n \leq 500000$

sol:

卡莫队的毒瘤题,需要 dsu on tree

大概就是 dfs 顺便维护一个数组叫“当前答案”,每次先把轻儿子加进来,再把重儿子加进来,然后把轻儿子删掉,重儿子继承这个“当前答案”数组

然后由于两点间最多有 log 条重链,复杂度很对劲

技术图片
#include <bits/stdc++.h>
#define LL long long
#define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
using namespace std;
inline int read() {
    int x = 0, f = 1; char ch;
    for (ch = getchar(); !isdigit(ch); ch = getchar()) if (ch == -) f = -f;
    for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - 0;
    return x * f;
}
const int maxn = 400010;
int n, m, a[maxn], b[maxn];
int first[maxn], to[maxn << 1], nx[maxn << 1], pnt;
inline void add(int u, int v) {
    to[++pnt] = v;
    nx[pnt] = first[u];
    first[u] = pnt;
}
int fa[maxn], mxs[maxn], size[maxn];
inline void dfs1(int x) {
    size[x] = 1;
    for(int i=first[x];i;i=nx[i]) {
        if(to[i] == fa[x]) continue;
        fa[to[i]] = x;
        dfs1(to[i]); size[x] += size[to[i]];
        if(size[to[i]] > size[mxs[x]]) mxs[x] = to[i];
    }
}
int cnt[maxn], now;
int ans[maxn], ansn[maxn];
inline void cal(int x, int opt) {
    cnt[b[x]] += opt * a[x];
    if((cnt[b[x]] > cnt[now]) || ((cnt[b[x]] == cnt[now]) && (b[x] < now) && (opt == 1))) now = b[x];
    for(int i=first[x];i;i=nx[i])
        if(to[i] != fa[x]) cal(to[i], opt);
}
inline void dfs(int x, int opt) {
    for(int i=first[x];i;i=nx[i])
        if(to[i] != fa[x] && to[i] != mxs[x]) dfs(to[i], 0);
    if(mxs[x]) dfs(mxs[x], 1);
    for(int i=first[x];i;i=nx[i])
        if(to[i] != fa[x] && to[i] != mxs[x]) cal(to[i], 1);
    cnt[b[x]] += a[x];
    if((cnt[b[x]] > cnt[now]) || ((cnt[b[x]] == cnt[now]) && (b[x] < now))) now = b[x];
    ans[x] = now; ansn[x] = cnt[now];
    if(!opt) now = 0, cal(x, -1);
}
int main() {
    n = read(), m = read();
    rep(i, 2, n) {
        int u = read(), v = read();
        add(u, v); add(v, u);
    } dfs1(1); cnt[0] = -1;
    rep(i, 1, n) b[i] = read(), a[i] = read();
    dfs(1, 1);
    rep(i, 1, n) printf("%d %d\n", ans[i], ansn[i]);
}
View Code

 

bzoj5457 城市

标签:alt   维护   \n   main   城市   c++   需要   div   log   

原文地址:https://www.cnblogs.com/Kong-Ruo/p/10515600.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!