1. 程式人生 > >CF600E Lomsat gelral(dsu on tree)

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 }