Jzoj3898 树的连通性

题意:给一棵树,每次删边或者询问连通性,强制在线

其实这题做法很多嘛,简单说一下

一眼看过去肯定是LCT啦,于是马上开始打

打到一半发现似乎不用LCT?好像树剖也可以嘛

结果发现树剖也不用,直接一个dfs序就可以了嘛

用线段树维护每个点能到达的最远的祖先,删边的时候将整个区间覆盖即可

注意,对于在子树中已经断开的节点不要再覆盖,可以记录每个节点深度

#pragma GCC opitmize("O3")
#pragma G++ opitmize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 200010
using namespace std;
struct Edge{ int v,nt; } G[N<<1];
int h[N],l[N],r[N],s[N<<2],v[N],n,m,cnt=0,clk=0,d[N];
inline void adj(int x,int y){ G[++cnt]=(Edge){y,h[x]}; h[x]=cnt; }
void dfs(int x,int p){
	l[x]=++clk; d[x]=d[p]+1;
	for(int v,i=h[x];i;i=G[i].nt)
		if((v=G[i].v)!=p) dfs(v,x);
	r[x]=clk;
}
inline void pd(int x){ //防止重复覆盖
	if(s[x]){
		int &ls=s[x<<1],&rs=s[x<<1|1];
		if(d[ls]<d[s[x]]) ls=s[x];
		if(d[rs]<d[s[x]]) rs=s[x];
		s[x]=0; 
	}
}
void update(int l,int r,int x,int L,int R,int k){
	if(L<=l && r<=R){ 
		if(!s[x]||d[s[x]]<d[k]) s[x]=k; return; 
	}
	pd(x); int m=l+r>>1;
	if(L<=m) update(l,m,x<<1,L,R,k);
	if(m<R) update(m+1,r,x<<1|1,L,R,k);
}
int query(int l,int r,int x,int k){
	if(l==r) return s[x];
	pd(x); int m=l+r>>1;
	if(k<=m) return query(l,m,x<<1,k);
	else return query(m+1,r,x<<1|1,k);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i) scanf("%d",v+i);
	for(int x,y,i=1;i<n;++i){
		scanf("%d%d",&x,&y);
		adj(x,y); adj(y,x);
	}
	dfs(1,0); int lst=0; s[1]=1;
	for(int o,a,b;m--;){
		scanf("%d%d%d",&o,&a,&b);
		a^=lst; b^=lst;
		if(o==1){
			if(l[b]>l[a]) a=b;
			update(1,n,1,l[a],r[a],a);
		} else if(o==2){
			if(query(1,n,1,l[a])==query(1,n,1,l[b]))
				printf("%d\n",lst=v[a]*v[b]);
			else printf("%d\n",lst=v[a]+v[b]);
		} else v[a]=b;
	}
}

posted @ 2017-10-03 19:38  扩展的灰(Extended_Ash)  阅读(102)  评论(0编辑  收藏  举报