CF600E Lomsat gelral(树上启发式合并)
虽然叫做dsu on tree,但是其实没有用到dsu,只是借鉴了dsu的启发式合并
启发式合并的精髓就是将轻节点的信息合并到重节点上,对轻节点进行暴力维护。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll,ll> pll; const int N=5e5+10; const int inf=0x3f3f3f3f; const int mod=772002; int n,col[N],flag; int son[N],sz[N]; int h[N],ne[N],e[N],idx; ll ans[N]; ll sum,mx; int cnt[N]; void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void dfs(int u,int fa){ int i; sz[u]=1; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa) continue; dfs(j,u); sz[u]+=sz[j]; if(sz[j]>sz[son[u]]){ son[u]=j; } } } void cal(int u,int fa,int val){ cnt[col[u]]+=val; if(cnt[col[u]]>mx){ mx=cnt[col[u]]; sum=col[u]; } else if(cnt[col[u]]==mx){ sum+=col[u]; } int i; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa||j==flag) continue; cal(j,u,val); } } void dfs1(int u,int fa,int keep){ int i; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa||j==son[u]) continue; dfs1(j,u,0); } if(son[u]){ dfs1(son[u],u,1); flag=son[u]; } cal(u,fa,1); ans[u]=sum; flag=0; if(!keep){ cal(u,fa,-1); sum=mx=0; } } int main(){ ios::sync_with_stdio(false); int i; cin>>n; memset(h,-1,sizeof h); for(i=1;i<=n;i++){ cin>>col[i]; } for(i=1;i<n;i++){ int a,b; cin>>a>>b; add(a,b); add(b,a); } dfs(1,-1); dfs1(1,-1,0); for(i=1;i<=n;i++) cout<<ans[i]<<" "; cout<<endl; return 0; }
没有人不辛苦,只有人不喊疼