差分+线段树合并 [Vani有约会]雨天的尾巴

似乎这题主流做法是树剖 但是树剖怎么做啊 线段树合并我还没怎么学过 所以用线段树合并来做了  

首先对于每个操作肯定是差分来维护是最方便的   

每个点我们建立一颗权值线段树  对于x y z 操作  

分别在树x,树y,树lca(x,y),树 fa[lca(x,y)] 上的z位置进行+1,+1,-1,-1的操作 这是典型的树上点差分 

然后我们由下而上的统计每棵树的答案就行了  

据说这种做法理论上只有nlogn的复杂的 不过常数巨大 可以比 nlognlogn的做法还慢    

一开始卡了两个点  吸氧能过  后来优化了两个常数 快读和求lca的常数(预处理logx) 总算是卡过了

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
#define mid (l+r>>1)
int fa[N][23],dep[N],rt[N],ans[N],lg[N];
int h[N],to[N<<1],nex[N<<1],cur;
inline int read(){
	int x = 0,w = 0;char c = 0;
	while(c<'0'||c>'9') w|=c=='-',c=getchar();
	while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return w?-x:x;
} 
void add_edge(int x,int y){
	to[++cur]=y;nex[cur]=h[x];h[x]=cur;
}
struct segment_tree{
	int mxv[N*50],mxp[N*50],L[N*50],R[N*50],tot;
	void pushup(int id){
		if(mxv[L[id]]>=mxv[R[id]]) mxv[id]=mxv[L[id]],mxp[id]=mxp[L[id]];
		else mxv[id]=mxv[R[id]],mxp[id]=mxp[R[id]];
		return;
	}
	void update(int &id,int l,int r,int pos,int val){
		if(!id) id=++tot;
		if(l==r){
			mxv[id]+=val,mxp[id]=l;return;
		}
		if(pos<=mid) update(L[id],l,mid,pos,val);
		else update(R[id],mid+1,r,pos,val);
		pushup(id);
	}
	int merge(int x,int y,int l,int r){
		if(!x||!y) return x+y;
		if(l==r){
			mxv[x]+=mxv[y],mxp[x]=l;return x; 
		}
		L[x]=merge(L[x],L[y],l,mid);
		R[x]=merge(R[x],R[y],mid+1,r);
		pushup(x);
		return x;
	}
}tr;
void dfs1(int u,int fath){
	fa[u][0]=fath;dep[u]=dep[fath]+1;
	for(int i = 1; i <= lg[dep[u]]; i++) fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int j = h[u]; j; j=nex[j]) if(to[j]!=fath) dfs1(to[j],u);
}
void dfs2(int u){
	for(int i = h[u]; i; i = nex[i]){
		if(to[i]!=fa[u][0]){
			dfs2(to[i]);
			rt[u]=tr.merge(rt[u],rt[to[i]],1,1e5);
		}
	}
	if(tr.mxv[rt[u]]==0) ans[u]=0;
	else ans[u]=tr.mxp[rt[u]];
}
int lca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	while(dep[x]>dep[y])  x=fa[x][lg[dep[x]-dep[y]]-1];
	if(x==y) return x;
	for(int i = lg[dep[x]-1]; i >= 0; i--)
		if(fa[x][i]!=fa[y][i])
		x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}

int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= n; i++) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
	for(int i = 1; i <= n-1; i++){
		int u,v;
		u=read(),v=read();
		add_edge(u,v);
		add_edge(v,u);
	} 
	dfs1(1,0);
	for(int i = 1; i <= m; i++){
		int x,y,z;
		x=read(),y=read(),z=read();
		int lc=lca(x,y);
		tr.update(rt[x],1,1e5,z,1);
		tr.update(rt[y],1,1e5,z,1);
		tr.update(rt[lc],1,1e5,z,-1);
		if(fa[lc][0]) tr.update(rt[fa[lc][0]],1,1e5,z,-1); 
	}
	dfs2(1);
	for(int i = 1; i <= n; i++) printf("%d\n",ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43824564/article/details/106317177
今日推荐