Codeforces600E Lomsat gelral
Codeforces600E Lomsat gelral
题目链接
题目大意
一棵树,1号节点为根,每个结点都有一个颜色,第i个节点的颜色为ci。
如果一种颜色在以x为根的子树内出现次数最多(可以不唯一),称其在以x为根的子树中占主导地位。
你的任务是对于每一个i∈[1,n],求出以i为根的子树中,占主导地位的颜色的编号和。
N<=10^5,ci<=n
Solution
dsu on tree (树上启发式合并)
不了解的可以看看这位大佬的博客,讲的很清楚
这里简述一下dsu的步骤就是:
(写在最前面)
记得开
记得开
记得开
(进入正题)
开两个变量,
lol res,maxn;//res保存当前数量最多的颜色的和,maxn保存当前数量最多的颜色的编号
然后我们通过以1为根节点遍历一遍树得到所有节点的重儿子
void dfs(lol u,lol fa) {
sz[u]=1;
for (lol i=head[u];i;i=nex[i]) {
if(to[i]==fa) continue;
dfs(to[i],u);
sz[u]+=sz[to[i]];
if(sz[to[i]]>sz[hson[u]]) hson[u]=to[i];//计算出每个节点的重儿子
}
}
然后进行遍历,先只遍历当前节点的轻儿子,碰到父亲节点或者重儿子就跳过
单独遍历重儿子
val表示遍历的是重儿子还是轻儿子,重儿子(val=1)的信息要保留,轻儿子(val=0)的信息在统计上答案之后要清除,
void dsu(lol u,lol fa,lol val) {
for (lol i=head[u];i;i=nex[i]) {
if(to[i]==fa || to[i]==hson[u]) continue;
dsu(to[i],u,0);
}
if(hson[u]) dsu(hson[u],u,1),HH=hson[u];
calc(u,fa,1);
HH=0;
dp[u]=res;
if(!val) calc(u,fa,-1),res=0,maxn=0;
}
在遍历完所有节点之后我们要再单独统计一下轻儿子的答案
这里说一下为什么单独再计算一次轻儿子的信息,因为重儿子的信息我们是保存下来的,但是轻儿子的信息每次计算后都会清除(这是dsu on tree的思想,重儿子只访问一遍,轻儿子要访问两遍),所以在统计以当前节点为根节点的答案的时候需要再统计一次轻儿子的信息
也就是这一段
calc(u,fa,1);
HH=0;
dp[u]=res;
到这里当前节点的答案就全部统计完毕了,我们可以保存下来,并把HH回溯(因为HH是全局变量,在返回上一层之后依然需要使用)
如果当前节点是作为轻儿子遍历的,那么我们在返回上一层时,需要清除当前节点的信息,即:
if(!val) calc(u,fa,-1),res=0,maxn=0;
下面是calc函数,用来计算轻儿子的信息,因此我们碰到重儿子的时候依然是需要跳过的
而当该函数用作清除函数的时候,此时HH必然已经清零,我们不会跳过以当前节点为根节点的子树中任何一个节点的信息
void calc(lol u,lol fa,lol val) {//val表示当前节点是统计信息还是清除信息
if(val==1) {
cnt[c[u]]++;
if(cnt[c[u]]>maxn) maxn=cnt[c[u]],res=c[u];
else if(cnt[c[u]]==maxn) res+=c[u];
}
else cnt[c[u]]--;
for (lol i=head[u];i;i=nex[i]) {
if(to[i]==fa || to[i]==HH) continue;
calc(to[i],u,val);
}
}
Code
#include<bits/stdc++.h>
#define lol long long//记得开long long
using namespace std;
const lol N=1e5+10;
lol n,cur;
lol head[N],nex[N<<1],to[N<<1];
lol cnt[N],dp[N];
lol sz[N];
lol hson[N];
lol HH;
lol c[N];
lol res,maxn;//res保存当前数量最多的颜色的和,maxn保存当前数量最多的颜色的编号
void add(lol a,lol b) {
to[++cur]=b,nex[cur]=head[a],head[a]=cur;//建边
}
void dfs(lol u,lol fa) {
sz[u]=1;
for (lol i=head[u];i;i=nex[i]) {
if(to[i]==fa) continue;
dfs(to[i],u);
sz[u]+=sz[to[i]];
if(sz[to[i]]>sz[hson[u]]) hson[u]=to[i];//计算出每个节点的重儿子
}
}
void calc(lol u,lol fa,lol val) {//val表示当前节点是统计信息还是清除信息
if(val==1) {
cnt[c[u]]++;
if(cnt[c[u]]>maxn) maxn=cnt[c[u]],res=c[u];
else if(cnt[c[u]]==maxn) res+=c[u];
}
else cnt[c[u]]--;
for (lol i=head[u];i;i=nex[i]) {
if(to[i]==fa || to[i]==HH) continue;
calc(to[i],u,val);
}
}
void dsu(lol u,lol fa,lol val) {
for (lol i=head[u];i;i=nex[i]) {
if(to[i]==fa || to[i]==hson[u]) continue;
dsu(to[i],u,0);
}
if(hson[u]) dsu(hson[u],u,1),HH=hson[u];
calc(u,fa,1);
HH=0;
dp[u]=res;
if(!val) calc(u,fa,-1),res=0,maxn=0;
}
int main() {
cin>>n;
for (lol i=1;i<=n;i++) cin>>c[i];
for (lol i=1,a,b;i<n;i++) {
cin>>a>>b;
add(a,b);
add(b,a);
}
dfs(1,0);
dsu(1,0,0);
for (lol i=1;i<=n;i++)
cout<<dp[i]<<" \n"[i==n];
return 0;
}
博主蒟蒻,随意转载.但必须附上原文链接
http://www.cnblogs.com/real-l/
http://www.cnblogs.com/real-l/
标签:
Codeforces
, 算法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现