D32 树上启发式合并 CF600E Lomsat gelral
视频链接:330 树上启发式合并 CF600E Lomsat gelral_哔哩哔哩_bilibili
#include <iostream> #include <cstring> #include <algorithm> #include <vector> #define LL long long using namespace std; int read(){ char c=getchar(); int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x*f; } const int N=1e5+10; // col[x]:节点的颜色编号, son[x]:重儿子, // cnt[i]:颜色编号i的数量 int n,col[N],siz[N],son[N],cnt[N],mx; LL sum,ans[N]; vector<int> e[N]; void dfs1(int x,int fa){ //重链剖分 siz[x]=1; for(int y : e[x]){ if(y==fa) continue; dfs1(y,x); siz[x]+=siz[y]; if(siz[y]>siz[son[x]]) son[x]=y; } } void add(int x,int fa,int son){ cnt[col[x]]++; if(cnt[col[x]]>mx) mx=cnt[col[x]],sum=col[x]; else if(cnt[col[x]]==mx) sum+=col[x]; for(int y : e[x]) //重子树除外 if(y!=fa && y!=son) add(y,x,son); } void sub(int x,int fa){ cnt[col[x]]--; for(int y : e[x]) if(y!=fa) sub(y,x); } void dfs2(int x, int fa, int opt){ for(int y : e[x]) //先搜轻儿子 if(y!=fa && y!=son[x]) dfs2(y,x,0); if(son[x]) dfs2(son[x],x,1); //后搜重儿子 add(x,fa,son[x]); //累加x和轻子树贡献 ans[x]=sum; //存储答案 if(!opt)sub(x,fa),sum=mx=0; //减掉轻子树贡献 } int main(){ n=read(); for(int i=1; i<=n; i++) col[i]=read(); for(int i=1; i<=n-1; i++){ int x=read(),y=read(); e[x].push_back(y); e[y].push_back(x); } dfs1(1,0); dfs2(1,0,0); for(int i=1; i<=n; i++) printf("%lld ",ans[i]); return 0; }
#include <iostream> #include <cstring> #include <algorithm> #include <vector> using namespace std; #define LL long long const int N=2e5+10; // col[x]:节点的颜色编号, son[x]:重儿子, // cnt[i]:颜色编号i的数量 int n,col[N],siz[N],son[N],cnt[N]; LL sum,ans[N]; vector<int> e[N]; void dfs1(int x,int fa){ //重链剖分 siz[x]=1; for(int y : e[x]){ if(y==fa) continue; dfs1(y,x); siz[x]+=siz[y]; if(siz[y]>siz[son[x]]) son[x]=y; } } void add(int x,int fa,int son){ if(!cnt[col[x]]) ++sum; cnt[col[x]]++; for(int y : e[x]) //重儿子除外 if(y!=fa && y!=son) add(y,x,son); } void sub(int x,int fa){ cnt[col[x]]--; for(int y : e[x]) if(y!=fa) sub(y,x); } void dfs2(int x, int fa, int opt){ for(int y : e[x]) //先搜轻儿子 if(y!=fa && y!=son[x]) dfs2(y,x,0); if(son[x]) dfs2(son[x],x,1); //后搜重儿子 add(x,fa,son[x]); //累加x和轻子树贡献 ans[x]=sum; //存储答案 if(!opt) sub(x,fa),sum=0; //减掉轻子树贡献 } int main(){ scanf("%d",&n); for(int i=1; i<n; i++){ int u,v; scanf("%d%d",&u,&v); e[u].push_back(v); e[v].push_back(u); } for(int i=1; i<=n; i++) scanf("%d",&col[i]); dfs1(1,0); dfs2(1,0,0); for(int i=1; i<=n; i++) printf("%d\n",ans[i]); return 0; }