标签:struct const for names 出现 个数 style main ide
给定一棵n个节点的树,每个节点有个权值,1为根节点。把任意节点为根的子树中权值出现次数最多的权值称为占领这个节点的权值。
然而次数最多的权值可能有多个,要求每个节点的占领这个节点所有权值的和。
每个子树上的答案互不相关,考虑用树上启发式合并。
用一个数组记录当前子树的所有权值出现的次数,有新的次数出现就给那个次数加上这个权值。
把非重儿子子树插入删除就好。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int M = 1e5+7; int n,a[M],head[M],cnt,tot,sz[M],son[M],tmp[M]; ll ans[M],sum[M]; struct edge{ int v,next; }e[M<<1]; void add(int u,int v){ e[++cnt].v=v;e[cnt].next=head[u]; head[u]=cnt; } void init(){ cnt=0;memset(head,-1,sizeof(head)); tot=0;memset(tmp,0,sizeof(tmp)); memset(sum,0,sizeof(sum)); } void dfs(int u,int fa){ sz[u]=1;son[u]=-1; for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==fa) continue; dfs(v,u); sz[u]+=sz[v]; if(son[u]==-1||sz[v]>sz[son[u]]) son[u]=v; } return ; } void addnode(int u){ sum[++tmp[a[u]]]+=a[u]; if(sum[tot+1]) tot+=1; } void delnode(int u){ sum[tmp[a[u]]--]-=a[u]; if(!sum[tot]) tot-=1; } void addtree(int u,int fa){ addnode(u); for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==fa) continue; addtree(v,u); } } void deltree(int u,int fa){ delnode(u); for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==fa) continue; deltree(v,u); } } void dfs1(int u,int fa){ for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==fa||v==son[u]) continue; dfs1(v,u); deltree(v,u); } if(son[u]!=-1) dfs1(son[u],u); for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==fa||v==son[u]) continue; addtree(v,u); } addnode(u); ans[u]=sum[tot]; } inline int read(){ int f=1,x=0;char ch; do{ch=getchar();if(ch==‘-‘)f=-1;}while(ch<‘0‘||ch>‘9‘); do{x=x*10+ch-‘0‘;ch=getchar();}while(ch>=‘0‘&&ch<=‘9‘); return f*x; } int main(){ init(); n=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<n;i++){ int u,v; u=read();v=read(); add(u,v);add(v,u); } dfs(1,-1); dfs1(1,-1); for(int i=1;i<=n;i++) printf("%lld%c",ans[i],i==n?‘\n‘:‘ ‘); return 0; }
标签:struct const for names 出现 个数 style main ide
原文地址:https://www.cnblogs.com/LMissher/p/9537745.html