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

每个节点上开一个cnti数组表示i这个数字出现了多少次,那么节点i上出现最多的数字就是cnt数组的最大值。

然后每次的操作可以调整为:

在u v上打一个+1的标记,在uv的lca上打一个-1的标记,在lca的父亲上打一个-1的标记。

然后打完标记后从叶子开始启发式的向上合并。

假设当前节点是u。

首先比较u的线段树sz和u的儿子们的最大线段树sz,小的往大的上面合并。

然后剩下的线段树无脑往这个最大的线段树上合并,那么最终的线段树就是u的状态。

然后题目要求输出最小的编号。

这里考虑直接在线段树上维护。

即id[i]表示节点i所在的区间内的最大值的最小编号。

然后往上pushup的时候应该是可以完全合并的。

另外,求lca可以直接倍增。

注意坑点:当一个点上最大次数为0的时候答案是0,不判断的话应该会输出1

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int M=maxn*80;
int tot;
int c[M],id[M],lson[M],rson[M],sz[M],T[maxn];
void pushup (int newRoot) {
	c[newRoot]=max(c[lson[newRoot]],c[rson[newRoot]]);
	if (c[lson[newRoot]]==c[newRoot]) id[newRoot]=id[lson[newRoot]];
	else id[newRoot]=id[rson[newRoot]];
	sz[newRoot]=sz[lson[newRoot]]+sz[rson[newRoot]]+1;
}
int up (int i,int l,int r,int p,int v) {
	int newRoot=i;
	if (!newRoot) newRoot=++tot,sz[newRoot]=1;
	if (l==r) {
		c[newRoot]+=v;
		id[newRoot]=l;
		return newRoot;
	}
	int mid=(l+r)>>1;
	if (p<=mid) lson[newRoot]=up(lson[newRoot],l,mid,p,v);
	if (p>mid) rson[newRoot]=up(rson[newRoot],mid+1,r,p,v);
	pushup(newRoot);
	return newRoot;
} 
int merge (int x,int y,int l,int r) {
	//合并根为x和y的线段树,返回新的根
	if (!x) return y;
	if (!y) return x;
	if (l==r) {
		c[x]+=c[y];
		return x;
	}
	if (sz[x]<sz[y]) swap(x,y);
	int mid=(l+r)>>1;
	lson[x]=merge(lson[x],lson[y],l,mid);
	rson[x]=merge(rson[x],rson[y],mid+1,r);
	pushup(x);
	return x;
}
int n;
vector<int> g[maxn];
int h[maxn],father[25][maxn];
void dfs (int x) {
	for (int y:g[x]) {
		if (y==father[0][x]) continue;
		father[0][y]=x;
		h[y]=h[x]+1;
		dfs(y);
	}
}
int lca (int x,int y) {
	if (h[x]<h[y]) swap(x,y);
	for (int i=20;i>=0;i--) {
		if (h[x]-h[y]>>i) x=father[i][x];
	}
	if (x==y) return x;
	for (int i=20;i>=0;i--) {
		if (father[i][x]!=father[i][y]) {
			x=father[i][x];
			y=father[i][y];
		}
	}
	return father[0][x];
}
int ans[maxn];
void dfs1 (int x) {
	for (int y:g[x]) {
		if (y==father[0][x]) continue;
		dfs1(y);
	}
	int maxson=-1,u=0;
	for (int y:g[x]) {
		if (y==father[0][x]) continue;
		if (sz[T[y]]>maxson) {
			maxson=sz[T[y]];
			u=y;
		}
	}
	if (u) T[x]=merge(T[x],T[u],1,1e5);
	for (int y:g[x]) {
		if (y==father[0][x]) continue;
		if (y==u) continue;
		T[x]=merge(T[x],T[y],1,1e5);
	}
	ans[x]=id[T[x]];
	if (c[T[x]]==0) ans[x]=0;
}
int m;
int main () {
	scanf("%d%d",&n,&m);
	for (int i=1;i<n;i++) {
		int x,y;
		scanf("%d%d",&x,&y);
		g[x].push_back(y);
		g[y].push_back(x);
	}
	dfs(1);
	for (int i=1;i<=20;i++) {
		for (int j=1;j<=n;j++) {
			father[i][j]=father[i-1][father[i-1][j]];
		}
	}
	while (m--) {
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		T[x]=up(T[x],1,1e5,z,1);
		T[y]=up(T[y],1,1e5,z,1);
		T[lca(x,y)]=up(T[lca(x,y)],1,1e5,z,-1);
		T[father[0][lca(x,y)]]=up(T[father[0][lca(x,y)]],1,1e5,z,-1);
	}
	dfs1(1);
	for (int i=1;i<=n;i++) printf("%d\n",ans[i]);
}
posted @ 2021-07-16 20:43  zlc0405  阅读(31)  评论(0编辑  收藏  举报