树上启发式合并-附有例题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
题面翻译
- 有一棵 \(n\) 个结点的以 \(1\) 号结点为根的有根树。
- 每个结点都有一个颜色,颜色是以编号表示的, \(i\) 号结点的颜色编号为 \(c_i\)。
- 如果一种颜色在以 \(x\) 为根的子树内出现次数最多,称其在以 \(x\) 为根的子树中占主导地位。显然,同一子树中可能有多种颜色占主导地位。
- 你的任务是对于每一个 \(i\in[1,n]\),求出以 \(i\) 为根的子树中,占主导地位的颜色的编号和。
- \(n\le 10^5,c_i\le n\)
题目描述
You are given a rooted tree with root in vertex $ 1 $ . Each vertex is coloured in some colour.
Let's call colour $ c $ dominating in the subtree of vertex $ v $ if there are no other colours that appear in the subtree of vertex $ v $ more times than colour $ c $ . So it's possible that two or more colours will be dominating in the subtree of some vertex.
The subtree of vertex $ v $ is the vertex $ v $ and all other vertices that contains vertex $ v $ in each path to the root.
For each vertex $ v $ find the sum of all dominating colours in the subtree of vertex $ v $ .
输入格式
The first line contains integer $ n $ ( $ 1<=n<=10^{5} $ ) — the number of vertices in the tree.
The second line contains $ n $ integers $ c_{i} $ ( $ 1<=c_{i}<=n $ ), $ c_{i} $ — the colour of the $ i $ -th vertex.
Each of the next $ n-1 $ lines contains two integers $ x_{j},y_{j} $ ( $ 1<=x_{j},y_{j}<=n $ ) — the edge of the tree. The first vertex is the root of the tree.
输出格式
Print $ n $ integers — the sums of dominating colours for each vertex.
样例 #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