1. 程式人生 > 其它 >CF600E Lomsat gelral 權值線段樹題解

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;
}