P4556 [Vani有约会]雨天的尾巴

P4556 [Vani有约会]雨天的尾巴

\(n\) 座房屋,并形成一个树状结构。然后救济粮分\(m\) 次发放,每次选择两个房屋 \((x,y)\),然后对于 \(x\)\(y\)的路径上(含\(x\)\(y\))每座房子里发放一袋 \(z\) 类型的救济粮。

然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。

紫色的板子,水题\(+1\)

每个节点维护一棵权值线段树,下标为救济粮种类,区间维护数量最多的救济粮编号。

然后树上点差分思想,最后统计时自底向上做树上前缀和、线段树合并即得当前节点信息。

/**
 *@ author:pyyyyyy/guhl37
 *@ bolg:https://www.cnblogs.com/pyyyyyy
 *@ Debug:
**/
#include <bits/stdc++.h>
using namespace std;
const int N = 4000045;
const int Log = 20;
struct Edeg{
	int v, Next;
}e[N];
int head[N], ecnt, cnt;
void add(int u,int v){
	e[++ecnt].Next = head[u];
	head[u] = ecnt;
	e[ecnt].v = v;
}
struct SegmentTree
{
	int ls, rs;
	int dat, pos;
}t[N << 2];
int root[N], num;
int f[N][21], dep[N], ans[N]; 
int n, m, val[N], X[N], Y[N], Z[N];
void dfs(int u, int fa){
	f[u][0] = fa;
	dep[u] = dep[fa] + 1;
	for(int i = 1; i <= Log; ++i)
		f[u][i] = f[f[u][i - 1]][i - 1];
	for(int i = head[u]; i; i = e[i].Next){
		int to = e[i].v;
		if(to == fa) continue;
		dfs(to, u);
	}
}
int lca(int x,int y){
	if(dep[x] < dep[y]) swap(x, y);
	for(int i = Log -1; i >= 0; --i)
		if(dep[f[x][i]] >= dep[y]) x = f[x][i];
	if(x == y) return x;
	for(int i = Log -1; i >= 0; --i)
		if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
	return f[x][0];	
}
void insert(int p, int l, int r, int val, int delta){
	if(l == r){
		t[p].dat += delta;
		t[p].pos = t[p].dat ? l : 0;
		return ;
	}
	int mid = (l + r) >> 1;
	if(val <= mid) {
		if(!t[p].ls) t[p].ls = ++num;
		insert(t[p].ls, l, mid, val, delta);
	}
	else{
		if(!t[p].rs) t[p].rs = ++num;
		insert(t[p].rs, mid + 1, r, val, delta);
	}
	t[p].dat = max(t[t[p].ls].dat, t[t[p].rs].dat);
	t[p].pos = t[t[p].ls].dat >= t[t[p].rs].dat ? t[t[p].ls].pos : t[t[p].rs].pos;
}
int merge(int p, int q, int l, int r){
	if(!p) return q;
	if(!q) return p;
	if(l == r){
		t[p].dat += t[q].dat;
		t[p].pos = t[p].dat ? l : 0;
		return p; 
	}
	int mid = (l + r) >> 1;
	t[p].ls = merge(t[p].ls, t[q].ls, l, mid);
	t[p].rs = merge(t[p].rs, t[q].rs, mid + 1, r);
	t[p].dat = max(t[t[p].ls].dat, t[t[p].rs].dat);
	t[p].pos = t[t[p].ls].dat >= t[t[p].rs].dat ? t[t[p].ls].pos : t[t[p].rs].pos;
	return p;
}
void search(int x){
	for(int i = head[x]; i; i = e[i].Next){
		int to = e[i].v;
		if(dep[to] <= dep[x]) continue;
		search(to);
		root[x] = merge(root[x], root[to], 1, cnt);
	}
	ans[x] = t[root[x]].pos;
}
int main()
{
//	freopen("input.in","r",stdin);
//	freopen(".out","w",stdout);
	cin >> n >> m;
	for(int i = 1; i < n; ++i){
		int x, y;
		scanf("%d %d",&x, &y);
		add(x, y);add(y, x);
	}
	dfs(1, 0);
//	for(int i = 1; i <= n; ++i) cout << dep[i] << ' ';
//	cout<<endl;
	for(int i = 1; i <= n; ++i) root[i] = ++num;
	for(int i = 1; i <= m; ++i) {
		scanf("%d %d %d",&X[i], &Y[i], &Z[i]);
		val[i] = Z[i];
	}
	sort(val + 1, val + m + 1);
	cnt = unique(val + 1, val + m + 1) - val - 1;
	for(int i = 1; i <= m; ++i){
		int x = X[i], y = Y[i];
		int z = lower_bound(val + 1, val + cnt, Z[i]) - val;
		int p = lca(x, y);
//		cout << z << '\n';
//		cout << x << ' ' << y << ' ' << p << '\n';
		insert(root[x], 1, cnt, z, 1);
		insert(root[y], 1, cnt, z, 1);
		insert(root[p], 1, cnt, z, -1);
		if(f[p][0]) insert(root[f[p][0]], 1, cnt, z, -1);
	}
	search(1);
//	for(int i = 1; i <= n; ++i) cout << ans[i] << ' ';
//	cout<<endl;
	for(int i = 1; i <= n; ++i) printf("%d\n", val[ans[i]]);
	return 0;
}

posted @ 2020-07-08 17:21  pyyyyyy  阅读(163)  评论(0编辑  收藏  举报