CF 600 E Lomsat gelral —— 树上启发式合并

题目:http://codeforces.com/contest/600/problem/E

看博客:https://blog.csdn.net/blue_kid/article/details/82192641

https://blog.csdn.net/clove_unique/article/details/60772212

还是不太明白复杂度...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const xn=1e5+5;
int n,c[xn],hd[xn],ct,to[xn<<1],nxt[xn<<1],cnt[xn],siz[xn],son[xn],mx,big;
ll ans[xn],sum;
void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;}
int rd()
{
    int ret=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
    while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
    return f?ret:-ret;
}
void dfs(int x,int fa)
{
    siz[x]=1;
    for(int i=hd[x],u;i;i=nxt[i])
    {
        if((u=to[i])==fa)continue;
        dfs(u,x); siz[x]+=siz[u];
        if(siz[u]>siz[son[x]])son[x]=u;
    }
}
void add(int x,int fa,int v)
{
    cnt[c[x]]+=v;
    if(cnt[c[x]]>mx)sum=c[x],mx=cnt[c[x]];
    else if(cnt[c[x]]==mx)sum+=c[x];
    for(int i=hd[x],u;i;i=nxt[i])
        if((u=to[i])!=fa&&u!=big)add(u,x,v);
}
void dfs2(int x,int fa,int keep)
{
    for(int i=hd[x],u;i;i=nxt[i])
        if((u=to[i])!=fa&&u!=son[x])dfs2(u,x,0);
    if(son[x])dfs2(son[x],x,1),big=son[x];
    add(x,fa,1); big=0;
    ans[x]=sum;
    if(!keep)add(x,fa,-1),mx=sum=0;//=0!
}
int main()
{
    n=rd();
    for(int i=1;i<=n;i++)c[i]=rd();
    for(int i=1,x,y;i<n;i++)
    {
        x=rd(); y=rd();
        add(x,y); add(y,x);
    }
    dfs(1,0); dfs2(1,0,0);
    for(int i=1;i<=n;i++)printf("%I64d ",ans[i]);
    return 0;
}

 

posted @ 2018-09-21 22:06  Zinn  阅读(175)  评论(0编辑  收藏  举报