[SDOI2017]树点涂色
树点涂色
题目链接:https://www.luogu.org/problemnew/show/P3703
lct
可以发现这题与lct的操作十分相似
颜色相同就在同一个splay里面
操作1:就是lct的access操作
操作2:co[u]表示u到根节点的颜色总数
ans=co[u]+co[v]-2*co[lca]+1,其实就是u节点到lca之前的颜色数+v节点到lca之前的颜色数+lca的颜色
操作3:查询一颗子树,可以考虑用dfs序+线段树维护子树的最大值
查询就正常的区间查询
当操作1修改时,access将轻边变成重边时,原来重边的子树多了一种颜色,区间+1
现在重边的子树少了一种颜色,区间-1
代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int M=1e5+9; 5 int n,m,num=0,id=0,df=0; 6 int L[M<<1],pw[23]; 7 int head[M],fir[M],dep[M],d[M<<1][23];struct P{int to,ne;}e[M<<1]; 8 int tid[M],pid[M],last[M],f[M],c[M][2]; 9 int Ma[M<<2],vi[M<<2]; 10 inline int read(){ 11 int rex=0,f=1;char ch=getchar(); 12 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0'&&ch<='9'){rex=rex*10+ch-'0';ch=getchar();} 14 return rex*f; 15 } 16 void dfs(int u,int fa){ 17 f[u]=fa;pid[tid[u]=++id]=u;dep[u]=dep[fa]+1;d[fir[u]=++df][0]=u; 18 for(int i=head[u];i;i=e[i].ne){ 19 int v=e[i].to; 20 if(v!=fa){dfs(v,u);d[++df][0]=u;} 21 } 22 last[u]=id; 23 } 24 inline int Min(int x,int y){ 25 return dep[x]<dep[y]?x:y; 26 } 27 inline int ask(int l,int r){ 28 l=fir[l],r=fir[r]; 29 if(l>r)swap(l,r); 30 int k=L[r-l+1]; 31 return Min(d[l][k],d[r-pw[k]+1][k]); 32 } 33 void build(int now,int l,int r){ 34 if(l==r){Ma[now]=dep[pid[l]];return;} 35 int mid=(l+r)>>1; 36 build(now<<1,l,mid); 37 build(now<<1|1,mid+1,r); 38 Ma[now]=max(Ma[now<<1],Ma[now<<1|1]); 39 } 40 void pushdown(int now,int l,int r){ 41 if(vi[now]){ 42 Ma[now]+=vi[now]; 43 if(l<r)vi[now<<1]+=vi[now]; 44 if(l<r)vi[now<<1|1]+=vi[now]; 45 vi[now]=0; 46 } 47 } 48 void pushup(int now,int l,int r){ 49 if(l==r)return; 50 int mid=(l+r)>>1; 51 pushdown(now<<1,l,mid); 52 pushdown(now<<1|1,mid+1,r); 53 Ma[now]=max(Ma[now<<1],Ma[now<<1|1]); 54 } 55 void update(int now,int l,int r,int x,int y,int p){ 56 pushdown(now,l,r); 57 if(x<=l&&r<=y){vi[now]+=p;return;} 58 int mid=(l+r)>>1; 59 if(x<=mid)update(now<<1,l,mid,x,y,p); 60 if(y>mid)update(now<<1|1,mid+1,r,x,y,p); 61 pushup(now,l,r); 62 } 63 int query(int now,int l,int r,int x,int y){ 64 pushdown(now,l,r); 65 if(x<=l&&r<=y)return Ma[now]; 66 int mid=(l+r)>>1,ans=0; 67 if(x<=mid)ans=max(ans,query(now<<1,l,mid,x,y)); 68 if(y>mid)ans=max(ans,query(now<<1|1,mid+1,r,x,y)); 69 return ans; 70 } 71 bool isroot(int x){ 72 return c[f[x]][0]!=x&&c[f[x]][1]!=x; 73 } 74 void rotate(int x){ 75 int y=f[x],z=f[y],k=c[y][1]==x,ch=c[x][k^1]; 76 if(!isroot(y))c[z][c[z][1]==y]=x;f[x]=z; 77 c[y][k]=ch;f[ch]=y; 78 c[x][k^1]=y;f[y]=x; 79 } 80 void splay(int x){ 81 for(int y=f[x];!isroot(x);y=f[x]){ 82 if(!isroot(y)) 83 rotate(((c[f[y]][1]==y)==(c[x][1]==x))?y:x); 84 rotate(x); 85 } 86 } 87 void access(int x){ 88 for(int t=0,s;x;t=x,x=f[x]){ 89 splay(x); 90 if(s=c[x][1]){ 91 while(c[s][0])s=c[s][0]; 92 update(1,1,n,tid[s],last[s],1); 93 } 94 if(c[x][1]=t){ 95 while(c[t][0])t=c[t][0]; 96 update(1,1,n,tid[t],last[t],-1); 97 } 98 } 99 } 100 int main(){ 101 n=read(),m=read(); 102 for(int i=1,u,v;i<n;++i){ 103 u=read(),v=read(); 104 e[++num]=(P){v,head[u]};head[u]=num; 105 e[++num]=(P){u,head[v]};head[v]=num; 106 } 107 dfs(1,0); 108 L[1]=0;pw[0]=1; 109 for(int i=1;i<=19;++i)pw[i]=pw[i-1]<<1; 110 for(int i=2;i<=df;++i)L[i]=L[i>>1]+1; 111 for(int j=1;j<=19;++j){ 112 for(int i=1;i+pw[j]-1<=df;++i){ 113 d[i][j]=Min(d[i][j-1],d[i+pw[j-1]][j-1]); 114 } 115 } 116 build(1,1,n); 117 for(int i=1,o,x,y,lc;i<=m;++i){ 118 o=read(),x=read(); 119 if(o==1)access(x); 120 if(o==2){ 121 y=read();lc=ask(x,y); 122 x=query(1,1,n,tid[x],tid[x]); 123 y=query(1,1,n,tid[y],tid[y]); 124 lc=query(1,1,n,tid[lc],tid[lc]); 125 printf("%d\n",x+y-lc*2+1); 126 } 127 if(o==3)printf("%d\n",query(1,1,n,tid[x],last[x])); 128 } 129 return 0; 130 }