/* 返回顶部 */

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

gate

线段树合并

设两个要合并的线段树为\(a\),\(b\)
\(a\)\(b\)不存在,则返回另一个。
否则,将\(b\)的数值累加到\(a\)上,并返回\(a\)
代码如下

int merge(int a,int b,int l,int r) {
	if(!a) return b;
	if(!b) return a;
	if(l == r) {
		mx[a] += mx[b];
		return a;
	}
	int mid = Mid;
	ls[a] = merge(ls[a],ls[b],l,mid);
	rs[a] = merge(rs[a],rs[b],mid+1,r);
	pushup(a);
	return a;
}

对于这道题,用线段树维护每个房屋获得的不同种类救济粮的个数和最大值,
用树上差分维护每个房屋。
\(sum[i]\)表示从\(1\)\(i\)的路径上都增加了\(i\)个,
则对于一次增加操作\((i,j)\)
\(sum[i]+1,sum[j]+1;sum[lca(i,j)]-1,sum[fa[lca(i,j)]-1\)
从下向上合并线段树。

debug:lca写错了,p[x][i]写成p[x][0]了,阿巴阿巴(1/1)

code

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define MogeKo qwq
using namespace std;

#define Mid (l+r>>1)

const int maxn = 6e6+5;
const int N = 1e5;

int n,m,x,y,z,cnt,tot;
int rt[N+5],ans[N+5];
int ls[maxn],rs[maxn],mx[maxn],id[maxn];
int dpth[N+5],p[N+5][25];
int head[N+5],to[N+5<<1],nxt[N+5<<1];


void add(int x,int y) {
	to[++cnt] = y;
	nxt[cnt] = head[x];
	head[x] = cnt;
}

void get_p(int u,int fa) {
	dpth[u] = dpth[fa]+1;
	p[u][0] = fa;
	for(int i = 1; (1<<i) <= dpth[u]; i++)
		p[u][i] = p[p[u][i-1]][i-1];
	for(int i = head[u]; i; i = nxt[i]) {
		int v = to[i];
		if(v == fa) continue;
		get_p(v,u);
	}
}

int Lca(int a,int b) {
	if(dpth[a] < dpth[b]) swap(a,b);
	for(int i = 20; i >= 0; i--) {
		if(dpth[a] - (1<<i) >= dpth[b])
			a = p[a][i];
	}
	if(a == b) return a;
	for(int i = 20; i >= 0; i--)
		if(p[a][i] != p[b][i])
			a = p[a][i], b = p[b][i];
	return p[a][0];
}

void pushup(int now) {
	if(mx[ls[now]] >= mx[rs[now]]) {
		mx[now] = mx[ls[now]];
		id[now] = id[ls[now]];
	} else {
		mx[now] = mx[rs[now]];
		id[now] = id[rs[now]];
	}
}

int modify(int now,int l,int r,int x,int val) {
	if(!now) now = ++tot;
	if(l == r) {
		mx[now] += val;
		id[now] = x;
		return now;
	}
	int mid = Mid;
	if(x <= mid) ls[now] = modify(ls[now],l,mid,x,val);
	else rs[now] = modify(rs[now],mid+1,r,x,val);
	pushup(now);
	return now;
}

int merge(int a,int b,int l,int r) {
	if(!a) return b;
	if(!b) return a;
	if(l == r) {
		mx[a] += mx[b];
		return a;
	}
	int mid = Mid;
	ls[a] = merge(ls[a],ls[b],l,mid);
	rs[a] = merge(rs[a],rs[b],mid+1,r);
	pushup(a);
	return a;
}

void dfs(int u,int fa) {
	for(int i = head[u]; i; i = nxt[i]) {
		int v = to[i];
		if(v == fa) continue;
		dfs(v,u);
		rt[u] = merge(rt[u],rt[v],1,N);
	}
	if(mx[rt[u]]) ans[u] = id[rt[u]];
}

int main() {
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= n-1; i++) {
		scanf("%d%d",&x,&y);
		add(x,y), add(y,x);
	}
	get_p(1,0);
	for(int i = 1; i <= m; i++) {
		scanf("%d%d%d",&x,&y,&z);
		int f = Lca(x,y);
		int ff = p[f][0];
		rt[x] = modify(rt[x],1,N,z,1);
		rt[y] = modify(rt[y],1,N,z,1);
		rt[f] = modify(rt[f],1,N,z,-1);
		if(ff) rt[ff] = modify(rt[ff],1,N,z,-1);
	}
	dfs(1,0);
	for(int i = 1; i <= n; i++)
		printf("%d\n",ans[i]);
	return 0;
}
posted @ 2020-07-27 17:50  Mogeko  阅读(153)  评论(0编辑  收藏  举报