CF#600E Lomsat gelral---DSU on tree


(https://codeforces.com/contest/600/problem/E)

Title Description

To give a \ (1 \) is the root of the tree, each node has a color \ (C_i \) , seeking a subtree at each point in the largest number of colors and color numbers appear.
\ (1 \ leq n \ leq 10 ^ 5,1 \ leq c_i \ leq n \)

sol:

\ (DSU \) is one such tool handle certain issues within the sub-tree, but does not support modification operations. First we need to split heavy chain, followed by light every time as long as the son of the son in heavy contribution towards violence and to. But if you think about it you will find, in fact, be considered a contribution to the re-light his son, so be sure to remember the influence after a node count complete answer should remove the light son.
But this complexity is why the time is right?
Consider first a conclusion, the number of the light strip on the path from the root to any point does not exceed \ (\ log n \) article, apparently because the light is not more than half the size of the son entire subtree. With this conclusion, in extreme cases, i.e. on a light path side is exactly the number of \ (\ log n-\) , and that at each side of the light will traverse the light statistical subtree, so complexity is \ (O (\ log n) \) multiplied by the complexity of the traverse. Consider traversal, each node is accessed only once, either when its ancestor node violence statistics son or eliminate the effects of light, or is it the answer to his own statistics, complexity \ (O (the n-) \) . Therefore, the total complexity of the \ (O (n-\ log n-) \) . (With mouth Hu ingredient)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
    int x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x;
}
const int N=100005;
int n,p[N],ban,h[N],maxn;
ll sum,ans[N];
int ver[N<<1],nxt[N<<1],head[N],tot;
int fa[N],son[N],siz[N];
inline void link(int x,int y){ver[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
void dfs1(int x,int la){
    fa[x]=la;siz[x]=1;
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(y==la) continue;
        dfs1(y,x);
        siz[x]+=siz[y];
        if(siz[y]>siz[son[x]]) son[x]=y;
    }
}
void update(int x,int val){
    h[p[x]]+=val;
    if(h[p[x]]>maxn) maxn=h[p[x]],sum=p[x];
    else if(h[p[x]]==maxn) sum+=p[x];
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(y==fa[x]||y==ban) continue;
        update(y,val);//每次都需要在整棵子树内删除某个点的贡献 
    }
}
void dfs2(int x,int opt){
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(y==fa[x]||y==son[x]) continue;
        dfs2(y,0);//暴力统计轻边的贡献,opt = 0表示递归完成后消除对该点的影响 
    }
    if(son[x]) dfs2(son[x],1);//统计重儿子的贡献,不消除影响 
    ban=son[x];update(x,1);//暴力统计所有轻儿子的贡献 
    ans[x]=sum;ban=0;
    if(!opt) update(x,-1),maxn=sum=0;//如果需要删除贡献的话就删掉 
}
int main(){
    n=read();
    for(int i=1;i<=n;i++) p[i]=read();
    for(int i=1;i<n;i++){
        int x=read(),y=read();
        link(x,y);link(y,x);
    }
    dfs1(1,0);dfs2(1,1);
    for(int i=1;i<=n;i++)
        printf("%I64d ",ans[i]);
    return 0;
}

Guess you like

Origin www.cnblogs.com/zxynothing/p/11627099.html