CF600E Lomsat gelral 权值线段树题解

link

前言

其实就是一道线段树合并的板子,因为机房要求写就写了。

题意

\(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;
}
posted @ 2021-07-16 12:11  Saintex  阅读(70)  评论(0编辑  收藏  举报