树上启发式合并-附有例题CF600E
树上启发式合并(dsu on tree)
但这个 dsu 应该和并查集没啥关系
总体思想就是利用重链剖分的性质,将小堆(轻儿子)往大堆(重儿子)合并,这样子可以达到 log 的复杂度
以下是几个重要函数
void dfs1(int u, int father){}
得到一系列重要数组,其中包括son[]
void dfs2(int u, int op){}
计算 u 子树的答案add_ans(int u, int xson){}
将 u 子树除了 xson 子树的所有加入答案,是合并轻子树的操作del_ans(int u){}
将 u 子树的答案删除,清空 cnt 数组,用于第一遍 dfs2 后轻子树的删除操作
第一次敲的时候 add_ans 函数敲成了 add 函数......
int n, m;
ll col[N];
int head[N], cnt;
struct Edge{
int from, to, nxt;
}e[N << 1];
void add(int u, int v){
e[++cnt].from = u;
e[cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
int deep[N], fa[N], siz[N], son[N];
void dfs1(int u, int father){
fa[u] = father;
deep[u] = deep[father] + 1;
siz[u] = 1;
for(int i = head[u]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(v == father) continue;
dfs1(v, u);
siz[u] += siz[v];
if(!son[u] || siz[son[u]] < siz[v]) son[u] = v;
}
}
ll tmpans, ans_cnt, num[N], ans[N];
void add_ans(int u, int xson){
num[col[u]]++;
if(num[col[u]] == ans_cnt){
tmpans += col[u];
}else if(num[col[u]] > ans_cnt){
ans_cnt = num[col[u]];
tmpans = col[u];
}
for(int i = head[u]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(v == xson || v == fa[u]) continue;
add_ans(v, xson);
}
}
void del_ans(int u){
num[col[u]]--;
for(int i = head[u]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(v == fa[u]) continue;
del_ans(v);
}
}
void dfs2(int u, int op){
for(int i = head[u]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(v == fa[u] || v == son[u]) continue;
dfs2(v, 0);
}
if(son[u] != 0){
dfs2(son[u], 1);
}
add_ans(u, son[u]);
ans[u] = tmpans;
if(op == 0){
tmpans = ans_cnt = 0;
del_ans(u);
}
}
再补一个 main 函数
点击查看代码
void solve() {
cin >> n;
for(int i = 1; i <= n; i++){
cin >> col[i];
}
for(int i = 1; i < n; i++){
int u, v;
cin >> u >> v;
add(u, v);
add(v, u);
}
dfs1(1, 0);
dfs2(1, 1);
for(int i = 1; i <= n; i++){
cout << ans[i] << " ";
}
}
Lomsat gelral
题面翻译
- 有一棵
个结点的以 号结点为根的有根树。 - 每个结点都有一个颜色,颜色是以编号表示的,
号结点的颜色编号为 。 - 如果一种颜色在以
为根的子树内出现次数最多,称其在以 为根的子树中占主导地位。显然,同一子树中可能有多种颜色占主导地位。 - 你的任务是对于每一个
,求出以 为根的子树中,占主导地位的颜色的编号和。
题目描述
You are given a rooted tree with root in vertex
Let's call colour
The subtree of vertex
For each vertex
输入格式
The first line contains integer
The second line contains
Each of the next
输出格式
Print
样例 #1
样例输入 #1
4
1 2 3 4
1 2
2 3
2 4
样例输出 #1
10 9 3 4
样例 #2
样例输入 #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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)