CF600E Lomsat gelral 树上启发式合并
发布日期:2021-05-09 04:44:19 浏览次数:11 分类:博客文章

本文共 1839 字,大约阅读时间需要 6 分钟。

题目描述

有一棵 \(n\) 个结点的以 \(1\) 号结点为根的有根树。

每个结点都有一个颜色,颜色是以编号表示的, \(i\) 号结点的颜色编号为 \(c_i\)​。
如果一种颜色在以 \(x\) 为根的子树内出现次数最多,称其在以 \(x\) 为根的子树中占主导地位。显然,同一子树中可能有多种颜色占主导地位。
你的任务是对于每一个 \(i\in[1,n]\),求出以 \(i\) 为根的子树中,占主导地位的颜色的编号和。
\(n≤10^5,c_i\le n\)

输入输出样例

输入 #1

4

1 2 3 4
1 2
2 3
2 4

输出 #1

10 9 3 4

输入 #2

15

1 2 3 1 2 3 3 1 1 3 2 2 1 2 3
1 2
1 3
1 4
1 14
1 15
2 5
2 6
2 7
3 8
3 9
3 10
4 11
4 12
4 13

输出 #2

6 5 4 3 2 3 3 1 1 3 2 2 1 2 3

分析

对于这一道题,因为一个子树递归结束后产生的影响会传递给下一个子树
所以在每一次计算之前都要清空贡献
但是这样做时间复杂度吃不消
其实 \(dfs\) 时有一个性质
对于一个节点,它所递归的最后一个子树的价值是不用清空的
而我们要尽量使这个子树保留的信息更多
因此我们选择这个节点的重儿子进行递归
对于轻儿子暴力删除和加入
复杂度证明请看洛谷日报

代码

#include
#include
inline int read(){ register int x=0,fh=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') fh=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*fh;}const int maxn=2e5+5;int h[maxn],tot=1;struct asd{ int to,nxt;}b[maxn];void ad(int aa,int bb){ b[tot].to=bb; b[tot].nxt=h[aa]; h[aa]=tot++;}int n,c[maxn],f[maxn],son[maxn],siz[maxn];void dfs(int now,int fa){ siz[now]=1; f[now]=fa; for(register int i=h[now];i!=-1;i=b[i].nxt){ register int u=b[i].to; if(u==fa) continue; dfs(u,now); siz[now]+=siz[u]; if(son[now]==0 || siz[son[now]]
mmax){ mmax=cnt[c[now]]; sum=c[now]; } else if(cnt[c[now]]==mmax){ sum+=c[now]; } for(int i=h[now];i!=-1;i=b[i].nxt){ int u=b[i].to; if(u==f[now] || u==orz) continue; xg(u,val); }}//删除/加入贡献void dfs2(int now,int op){ for(register int i=h[now];i!=-1;i=b[i].nxt){ register int u=b[i].to; if(u==f[now] || u==son[now]) continue; dfs2(u,0); } if(son[now]){ dfs2(son[now],1); orz=son[now]; } xg(now,1); orz=0; ans[now]=sum; if(op==0){ xg(now,-1); sum=mmax=0; }}//求出答案int main(){ memset(h,-1,sizeof(h)); n=read(); for(register int i=1;i<=n;i++){ c[i]=read(); } int aa,bb; for(register int i=1;i
上一篇:CF538B Quasi Binary 思维题
下一篇:联赛模拟测试9 C. 小奇的仓库(warehouse)

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2025年04月19日 20时12分15秒