CF600E Lomsat gelral(dsu on tree)

一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,如果一个子树中某种颜色的出现次数最多,则称这棵子树被这种颜色占领(可能被多种颜色占领),问以每一个节点为根的子树,占领它的颜色的编号之和

这题的做法好像是一个叫做dsu on tree的东西(dsu似乎是并查集的缩写?然而和并查集没什么关系啊……)

这题目虽然dfs序套莫队也能做,不过我们考虑一下暴力的方法

我们在统计节点u之前,把u的所有子树的贡献都加入答案,然后在暴力把所有的贡献都清楚

然而这样会有很多的无用的删除操作

我们考虑先把原树给轻重链剖分,然后统计子树贡献的时候,在处理完轻儿子的答案之后,把他们的影响给消除,但处理完重儿子的答案之后,不必把影响消除

这样的话顺序就是先处理轻儿子的答案并消除影响,然后处理重儿子,保留影响,再去处理一遍轻儿子来求出当前子树的答案

因为轻重链剖分之后一个点到根的路径上最多有$O(logn)$条轻边,所以每个节点只会被统计与删除$O(logn)$次,总复杂度就是$O(nlogn)$

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4 #define ll long long
 5 using namespace std;
 6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 7 char buf[1<<21],*p1=buf,*p2=buf;
 8 int read(){
 9     #define num ch-'0'
10     char ch;bool flag=0;int res;
11     while(!isdigit(ch=getc()))
12     (ch=='-')&&(flag=true);
13     for(res=num;isdigit(ch=getc());res=res*10+num);
14     (flag)&&(res=-res);
15     #undef num
16     return res;
17 }
18 char sr[1<<21],z[20];int C=-1,Z;
19 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
20 void print(ll x){
21     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
22     while(z[++Z]=x%10+48,x/=10);
23     while(sr[++C]=z[Z],--Z);sr[++C]=' ';
24 }
25 const int N=2e5+5;
26 int head[N],Next[N<<1],ver[N<<1],tot;
27 void add(int u,int v){
28     ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
29 }
30 int n,c[N],val[N],sz[N],son[N];ll ans[N];
31 void dfs1(int u,int fa=0){
32     sz[u]=1;
33     for(int i=head[u];i;i=Next[i]){
34         int v=ver[i];
35         if(v!=fa){
36             dfs1(v,u),sz[u]+=sz[v];
37             if(sz[son[u]]<sz[v]) son[u]=v;
38         }
39     }
40 }
41 bool vis[N];int mx=0;ll sum=0;
42 void update(int u,int fa,int k){
43     c[val[u]]+=k;
44     if(k>0&&c[val[u]]>=mx){
45         if(c[val[u]]>mx) sum=0,mx=c[val[u]];
46         sum+=val[u];
47     }
48     for(int i=head[u];i;i=Next[i])
49     if(ver[i]!=fa&&!vis[ver[i]]) update(ver[i],u,k);
50 }
51 void dfs2(int u,int fa=0,bool used=0){
52     for(int i=head[u];i;i=Next[i]){
53         int v=ver[i];if(v!=fa&&v!=son[u]) dfs2(v,u);
54     }
55     if(son[u]) dfs2(son[u],u,1),vis[son[u]]=1;
56     update(u,fa,1),ans[u]=sum;
57     if(son[u]) vis[son[u]]=0;
58     if(!used) update(u,fa,-1),mx=sum=0;
59 }
60 int main(){
61 //    freopen("testdata.in","r",stdin);
62     n=read();
63     for(int i=1;i<=n;++i) val[i]=read();
64     for(int i=1;i<n;++i){
65         int u=read(),v=read();add(u,v),add(v,u);
66     }
67     dfs1(1),dfs2(1);
68     for(int i=1;i<=n;++i) print(ans[i]);
69     return Ot(),0;
70 }

猜你喜欢

转载自www.cnblogs.com/bztMinamoto/p/9815915.html