Jzoj3898 树的连通性

来源:互联网 发布:钢结构强度校核软件 编辑:程序博客网 时间:2024/06/05 11:05

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

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

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

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

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

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

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

#pragma GCC opitmize("O3")#pragma G++ opitmize("O3")#include<stdio.h>#include<string.h>#include<algorithm>#define N 200010using 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;}}