P4556 [Vani有约会]雨天的尾巴 /[模板] 线段树合并

树上差分 + 线段树合并
以每个点为根节点建立一棵权值线段树记录now(当前最多的粮食的种类) 和 size(最多的粮食的数量)
每棵线段树的叶节点 的下标就是粮食的种类a
最后合并每棵权值线段树就好啦

#include <bits/stdc++.h>
using namespace std;
#define mid (l + r) / 2
const int N = 1e5 + 5;

int n, m, cnt, tot, t;
int to[N << 1], head[N], nex[N << 1];
int ans[N], deep[N], f[N][50];
int ls[N * 80], rs[N * 80], root[N], size[N * 80], now[N * 80];

void add(int x, int y) {
	nex[++cnt] = head[x];
	to[cnt] = y;
	head[x] = cnt;
}
void dfs(int x, int dep) {
	deep[x] = dep;
	for(int i = 1; i <= t; i++)
		f[x][i] = f[f[x][i - 1]][i - 1];
	for(int i = head[x]; i; i = nex[i]) {
		int y = to[i];
		if(deep[y]) continue;
		f[y][0] = x;
		dfs(y, dep + 1);
	}
}
int LCA(int x, int y) {
	if(deep[x] > deep[y]) swap(x, y);
	for(int i = t; i >= 0; i--)
		if(deep[f[y][i]] >= deep[x]) y = f[y][i];
	if(x == y) return x;
	for(int i = t; i >= 0; i--)
		if(f[y][i] != f[x][i]) x = f[x][i], y = f[y][i];
	return f[x][0];
}
void up(int x) {
	if(size[ls[x]] >= size[rs[x]])
		size[x] = size[ls[x]], now[x] = now[ls[x]];
	else size[x] = size[rs[x]], now[x] = now[rs[x]];
}
int merge(int x, int y, int l, int r) { // 合并操作
	if(!x || !y) return x + y;
	if(l == r) {
		size[x] += size[y];
		now[x] = l;
		return x;
	}
	ls[x] = merge(ls[x], ls[y], l, mid);
	rs[x] = merge(rs[x], rs[y], mid + 1, r);
	up(x);
	return x;
}
void change(int &u, int l, int r, int num, int k) { 
	if(!u) u = ++tot;
	if(l == r) {
		size[u] += k;
		now[u] = l;
		return ;
	}
	if(num <= mid) change(ls[u], l, mid, num, k);
	else change(rs[u], mid + 1, r, num, k);
	up(u);
}
void cacl(int x) { // 合并每一棵线段树
	for(int i = head[x]; i; i = nex[i]) {
		int y = to[i];
		if(y == f[x][0]) continue;
		cacl(y);
		root[x] = merge(root[x], root[y], 1, N - 5);
	}
	if(size[root[x]] && now[root[x]]) ans[x] = now[root[x]];
	else ans[x] = 0;
}
int main() {
	ios :: sync_with_stdio(0);

	cin >> n >> m;
	t = (log(n) / log(2)) + 1;
	for(int i = 1; i < n; i++) {
		int a, b;
		cin >> a >> b;
		add(a, b);
		add(b, a);
	}
	dfs(1, 1);
	for(int i = 1; i <= m; i++) {
		int x, y, z;
		cin >> x >> y >> z;
		int lca = LCA(x, y);
		change(root[x], 1, N - 5, z, 1); //  z <= 1e5
		change(root[y], 1, N - 5, z, 1);
		change(root[lca], 1, N - 5, z, -1);
		change(root[f[lca][0]], 1, N - 5, z, -1);
	}
	cacl(1);
	for(int i = 1; i <= n; i++) cout << ans[i] << endl;
	return 0;
}
posted @ 2020-10-16 16:14  月夭  阅读(86)  评论(0编辑  收藏  举报