CF600E Lomsat gelral 权值线段树题解
前言
其实就是一道线段树合并的板子,因为机房要求写就写了。
题意
问 \(1\sim n\) 的子树中各个子树的众数和。
分析
其实,一般如果要求各个子树的某个东西,我们一般都是考虑 线段树合并/dsu on tree/dfn+其他数据结构(可能还有其他做法,只不过我太菜了不会),所以我才会说显然。
考虑将每个点都建一棵权值线段树,跑一次 \(dfs\), 将子树 合并,然后线段树中维护我们想要的东西,在这道题中就是数字出现的 最大次数 和 众数和。
关于时间复杂度:对于每次底层的合并,都会使两个数绑成一块,那最多进行 \(n\) 次,每次跑到底层需要 \(log_2(n)\),则时间复杂度:\(\mathcal {O}(nlog_2(n))\)。
关于左右区间合并,若出现的次数相等,贡献为两边相加,否则为次数大的那个。
Code
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#define LL long long
using namespace std;
const int MAXN = 1e5 + 5;
struct Segment_Tree {
int L, R, Max;
LL Sum;
}tree[MAXN * 65];
int n, a[MAXN], tot, root[MAXN];
LL ans[MAXN];
vector <int> v[MAXN];
int max_(int x, int y) { return x > y ? x : y; }
int add(int p, int x, int l, int r) {
if(!p) p = ++ tot;
if(l == r) { tree[p].Max = 1; tree[p].Sum = x; return p; }
int mid = (l + r) >> 1;
if(x <= mid) tree[p].L = add(tree[p].L, x, l, mid);
else tree[p].R = add(tree[p].R, x, mid + 1, r);
if(tree[tree[p].L].Max == tree[tree[p].R].Max) tree[p].Sum = tree[tree[p].L].Sum + tree[tree[p].R].Sum, tree[p].Max = max_(tree[tree[p].L].Max, tree[tree[p].R].Max);
else tree[p].Max = max_(tree[tree[p].L].Max, tree[tree[p].R].Max), tree[p].Sum = tree[tree[p].L].Max >= tree[tree[p].R].Max ? tree[tree[p].L].Sum : tree[tree[p].R].Sum;
return p;
}
int Merge(int p, int q, int l, int r) {
if(!p) return q;
if(!q) return p;
if(l == r) {
tree[p].Max += tree[q].Max; tree[p].Sum = tree[q].Sum;
return p;
}
int mid = (l + r) >> 1;
tree[p].L = Merge(tree[p].L, tree[q].L, l, mid);
tree[p].R = Merge(tree[p].R, tree[q].R, mid + 1, r);
if(tree[tree[p].L].Max == tree[tree[p].R].Max) tree[p].Sum = tree[tree[p].L].Sum + tree[tree[p].R].Sum, tree[p].Max = max_(tree[tree[p].L].Max, tree[tree[p].R].Max);
else tree[p].Max = max_(tree[tree[p].L].Max, tree[tree[p].R].Max), tree[p].Sum = tree[tree[p].L].Max >= tree[tree[p].R].Max ? tree[tree[p].L].Sum : tree[tree[p].R].Sum;
// printf("%d %d %d %lld\n", l, r, tree[p].Max, tree[p].Sum);
return p;
}
void dfs(int x, int fa) {
for(unsigned int i = 0; i < v[x].size(); i ++) {
int y = v[x][i]; if(y == fa) continue;
dfs(y, x); root[x] = Merge(root[x], root[y], 1, n);
}
ans[x] = tree[root[x]].Sum;
}
int main() {
int x, y;
scanf("%d", &n); tot = n;
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]), root[i] = i, root[i] = add(root[i], a[i], 1, n);
for(int i = 1; i < n; i ++) {
scanf("%d%d", &x, &y); v[x].push_back(y); v[y].push_back(x);
}
dfs(1, -1);
for(int i = 1; i <= n; i ++) printf("%lld ", ans[i]);
return 0;
}