题解 P3703 【[SDOI2017]树点涂色】

Newuser

2018-04-11 16:15:34

Solution

//本蒟蒻博客的同步阅读:[Newuser小站!](http://www.newuser.top/2018/04/11/shudiantuse/) 这不是纯种的LCT,,,,是LCT+LCA+DFS序(或者重链剖分)+线段树,最近学的全用进来了,,很有喧宾夺主的意味。。。 首先他是每一次都涂一种不同的颜色,就不用具体存储具体的颜色。 我们看到第1个操作,这和LCT的ACCESE很有相似之处。于是我们就想到,设定一个SPLAY就是一个颜色集合的话,那么这个操作1就是一个裸的ACCES操作就好了 第2个操作求AB两点间的路径上的权值,转化为节点到根经过了多少个splay,num[x],num[a]+num[b]-num[lca(a,b)]*2+1 第3个操作求子树里面的最大num,可以dfs序+线段树维护。 设定num[x]为从x节点开始,往上走到根经过了多少个splay,在开始的时候所有节点都各自为一个splay,此时的num[x]就是每一个节点的深度dep,在dfs的时候就可以搞出来。 想到这个LCT,没有link,没有cut,只有虚实边的转化,于是乎只有Acces会调整他的num值(切换左右儿子的时候)。考虑到每连上去一条边,原本连到的那个结点(切换点的后继)的子树从 id[x]到id[x]+siz[x]-1都会加上一个1(多了一个虚边多了一个到根节点的splay),之后连到的那个结点的id[x]+siz[x]-1都会减去一个1。 我们考虑线段树维护其区间max,每次ACCES加减就是max的区间修改,而第三问则直接询问子树上的区间Max。 注意我们splay维护的dfs序,在考虑切换重边的时候要考虑到找到深度最小的点(因为这个卡了两个小时的蒟蒻)。 要找LCA,由于这其实是一个静态的树,我们可以LCA转RMQ,,由于本蒟蒻很弱,直接写的倍增。。。 于是就搞定啦! code: ```cpp #include<stdio.h> #include<bits/stdc++.h> #define midd ((l+r)>>1) #define zig(x) zigzag(x,1) #define zag(x) zigzag(x,2) using namespace std; int n,m; int owo,la[100005],nt[200005],en[200005]; void addedge(int a,int b) { en[++owo]=b; nt[owo]=la[a]; la[a]=owo; } int idcnt,id[100005],old[100005],maxr[100005],dep[100005]; int fa[100005],ls[100005],rs[100005]; struct node { int ll,rr,mx,lazy; }z[8*100005]; void maketree(int p,int l,int r) { z[p].ll=l; z[p].rr=r; if(l==r) { z[p].mx=dep[old[l]]; return; } maketree(p<<1,l,midd); maketree(p<<1|1,midd+1,r); z[p].mx=max(z[p<<1].mx,z[p<<1|1].mx); } void ppd(int p) { if(z[p].ll==z[p].rr||(!z[p].lazy)) return; z[p<<1].lazy+=z[p].lazy; z[p<<1|1].lazy+=z[p].lazy; z[p<<1].mx+=z[p].lazy; z[p<<1|1].mx+=z[p].lazy; z[p].lazy=0; } bool isroot(int x) { return ((!fa[x])||(ls[fa[x]]!=x&&rs[fa[x]]!=x)); } void zigzag(int x,int knd) { int y=fa[x]; int z=fa[y]; if(!isroot(y)) { if(ls[z]==y) ls[z]=x; else rs[z]=x; } fa[x]=z; fa[y]=x; if(knd==1) { ls[y]=rs[x]; fa[ls[y]]=y; rs[x]=y; } else { rs[y]=ls[x]; fa[rs[y]]=y; ls[x]=y; } } void splay(int x) { int y,z; while(!isroot(x)) { y=fa[x]; z=fa[y]; if(isroot(y)) { if(ls[y]==x) zig(x); else zag(x); } else { if(ls[z]==y) { if(ls[y]==x) { zig(y); zig(x); } else { zag(x); zig(x); } } else { if(rs[y]==x) { zag(y); zag(x); } else { zig(x); zag(x); } } } } } void update(int p,int x,int y,int d) { if(x<=z[p].ll&&z[p].rr<=y) { z[p].mx+=d; z[p].lazy+=d; return; } if(z[p].lazy) ppd(p); if(z[p<<1].rr>=x&&z[p<<1].ll<=y) update(p<<1,x,y,d); if(z[p<<1|1].rr>=x&&z[p<<1|1].ll<=y) update(p<<1|1,x,y,d); z[p].mx=max(z[p<<1|1].mx,z[p<<1].mx); } int mmm(int x) { while(ls[x]) x=ls[x]; return x; } void acc(int x) { for(int y=0;x;y=x,x=fa[x]) { splay(x); if(rs[x]) { int z=mmm(rs[x]); update(1,id[z],maxr[z],1); } rs[x]=y; if(y) { int z=mmm(y); update(1,id[z],maxr[z],-1); } } } int getmax(int p,int x,int y) { if(x<=z[p].ll&&z[p].rr<=y) return z[p].mx; if(z[p].lazy) ppd(p); int lmax=-0x3f3f3f3f,rmax=-0x3f3f3f3f; if(z[p<<1].rr>=x&&z[p<<1].ll<=y) lmax=getmax(p<<1,x,y); if(z[p<<1|1].rr>=x&&z[p<<1|1].ll<=y) rmax=getmax(p<<1|1,x,y); return max(lmax,rmax); } int pa[100005][30]; int lcaa(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int k=dep[x]-dep[y],i=0;k;i++,k>>=1) { if(k&1) x=pa[x][i]; } if(x==y) return x; for(int k=20;k>=0;k--) { if(pa[x][k]!=pa[y][k]) { x=pa[x][k]; y=pa[y][k]; } } return pa[x][0]; } void dfs(int x,int ba) { pa[x][0]=ba; dep[x]=dep[ba]+1; for(int k=20,i=1;i<=k;i++) pa[x][i]=pa[pa[x][i-1]][i-1]; fa[x]=ba; id[x]=++idcnt; old[idcnt]=x; for(int it=la[x];it;it=nt[it]) { if(en[it]!=ba) { dfs(en[it],x); } } maxr[x]=idcnt; } int query(int p,int x) { if(z[p].ll==z[p].rr) return z[p].mx; if(z[p].lazy) ppd(p); if(x<=z[p<<1].rr) return query(p<<1,x); else return query(p<<1|1,x); } int main() { // freopen("date.in","r",stdin); // freopen("zhengjie.out","w",stdout); int a,b; scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { scanf("%d%d",&a,&b); addedge(a,b); addedge(b,a); } dfs(1,0); maketree(1,1,n); int kkk,x; for(int i=1;i<=m;i++) { scanf("%d",&kkk); if(kkk==1) { scanf("%d",&x); acc(x); } else if(kkk==2) { scanf("%d%d",&a,&b); int aha=lcaa(a,b); int aaaa=query(1,id[a])+query(1,id[b])-query(1,id[aha])*2+1; printf("%d\n",aaaa); } else { scanf("%d",&a); printf("%d\n",getmax(1,id[a],maxr[a])); } } } ```