涂色的操作和 a c c e s s access access很像啊,如何用 L C T LCT LCT维护这个东西呢。
由于每次覆盖的颜色都不同,且是从当前到结点覆盖到根节点。
那么如果把颜色相同的一段维护在一条重链上,
一个点到根要经过多少虚边也就包含多少颜色。
所以用
L
C
T
LCT
LCT模拟覆盖的过程,用线段树维护即可。
虚变实就是子树减,实变虚就是子树加。
询问1就是
v
a
l
[
x
]
+
v
a
l
[
y
]
−
2
∗
v
a
l
[
l
c
a
(
x
,
y
)
]
+
1
val[x]+val[y]-2*val[lca(x,y)]+1
val[x]+val[y]−2∗val[lca(x,y)]+1,
询问3就是区间最大值。
写的时候要想好
L
C
T
LCT
LCT在原树中的对应点。
以及初始的时候是一个点一个
s
p
l
a
y
splay
splay。
#include<bits/stdc++.h>
#define re register
#define cs const
using std::swap;
cs int N=1e5+10;
int Head[N],Next[N<<1],V[N<<1],cnt=0;
int siz[N],dep[N],top[N],fa[N],son[N],L[N],R[N],t[N],tot=0;
namespace IO{
cs int Rlen=1<<22|1;
char buf[Rlen],*p1,*p2;
inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}
template<typename T>
inline T get(){
char ch=gc();T x=0;
while(!isdigit(ch)) ch=gc();
while(isdigit(ch)) x=((x+(x<<2))<<1)+(ch^48),ch=gc();
return x;
}
inline int gi(){return get<int>();}
}
using IO::gi;
int n,m,u,v,g,op;
namespace SGT{
#define lc (root<<1)
#define rc (root<<1|1)
#define mid (T[root].l+T[root].r>>1)
struct node{int l,r,tag,mx;}T[N<<2];
inline void pushup(int root){T[root].mx=std::max(T[lc].mx,T[rc].mx);}
inline void pushnow(int root,int val){T[root].mx+=val,T[root].tag+=val;}
inline void pushdown(int root){
if(T[root].tag){
pushnow(lc,T[root].tag),
pushnow(rc,T[root].tag),
T[root].tag=0;
}
}
inline void build(int root,int l,int r){
T[root].l=l,T[root].r=r;
if(l==r){T[root].mx=dep[t[l]],T[root].tag=0;return;}
build(lc,l,mid),build(rc,mid+1,r),pushup(root);
}
inline void update(int root,int l,int r,int val){
if(l<=T[root].l&&T[root].r<=r) return pushnow(root,val);
pushdown(root);
if(l> mid) return update(rc,l,r,val),pushup(root);
if(r<=mid) return update(lc,l,r,val),pushup(root);
update(lc,l,mid,val),update(rc,mid+1,r,val),pushup(root);
}
inline int query_max(int root,int l,int r){
if(l<=T[root].l&&T[root].r<=r) return T[root].mx;
pushdown(root);
if(l> mid) return query_max(rc,l,r);
if(r<=mid) return query_max(lc,l,r);
return std::max(query_max(lc,l,mid),query_max(rc,mid+1,r));
}
inline int val(int root,int pos){
if(T[root].l==T[root].r) return T[root].mx;
pushdown(root);
return pos<=mid?val(lc,pos):val(rc,pos);
}
#undef lc
#undef rc
#undef mid
}
using SGT::val;
namespace LCT{
int son[N][2],fa[N];
inline int get(int x){return x==son[fa[x]][1];}
inline int isroot(int x){return (!fa[x])||(x!=son[fa[x]][0]&&x!=son[fa[x]][1]);}
inline void rotate(int x){
int y=fa[x],z=fa[y],k=get(x),l=son[x][k^1];
if(!isroot(y)) son[z][get(y)]=x;
fa[x]=z,fa[y]=x,son[x][k^1]=y;
fa[l]=y,son[y][k]=l;
}
inline void splay(int x){
for(int re y=fa[x];!isroot(x);rotate(x),y=fa[x])
if(!isroot(y)) rotate(get(y)==get(x)?y:x);
}
inline int getpos(int x){
while(son[x][0]) x=son[x][0];
return x;
}
inline void access(int x){
for(int re y=0,pos;x;y=x,x=fa[x]){
splay(x),pos=getpos(son[x][1]);
if(pos) SGT::update(1,L[pos],R[pos],1);
son[x][1]=y,pos=getpos(y);
if(pos) SGT::update(1,L[pos],R[pos],-1);
}
}
}
inline void add(int u,int v){Next[++cnt]=Head[u],V[cnt]=v,Head[u]=cnt;}
void dfs1(int u,int f){
siz[u]=1,son[u]=0,fa[u]=f,dep[u]=dep[f]+1,LCT::fa[u]=f;
for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]])
if(v!=f){dfs1(v,u),siz[u]+=siz[v];if(siz[v]>siz[son[u]]) son[u]=v;}
}
void dfs2(int u,int tp){
t[L[u]=++tot]=u,top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(int re i=Head[u],v=V[i];i;v=V[i=Next[i]])
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
R[u]=tot;
}
inline int lca(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}return (dep[u]<dep[v])?u:v;
}
int main(){
// freopen("2301.in","r",stdin);
n=gi(),m=gi();
for(int re i=1;i< n;++i) u=gi(),v=gi(),add(u,v),add(v,u);
dfs1(1,0),dfs2(1,1),SGT::build(1,1,n);
while(m--){
op=gi();
if(op==1) u=gi(),LCT::access(u);
if(op==2) u=gi(),v=gi(),g=lca(u,v),printf("%d\n",val(1,L[u])+val(1,L[v])-2*val(1,L[g])+1);
if(op==3) u=gi(),printf("%d\n",SGT::query_max(1,L[u],R[u]));
}
}