ETT维护欧拉序。每个点维护它的深度,出点入点基本无异。
第一个操作求个lca就好了qaq,x,y的lca就是(in[x],out[y])中深度最小的点的父亲。
第二个操作,x的kth祖先,就是[1,in[x]]中最靠右的深度为dep[x]-k的点。
第三个操作,我们注意到欧拉序上一段连续的区间的深度是连续的,于是我们可以维护每个区间的深度最小/最大值,然后二分来找到深度k的最后一个出现位置,直接在splay上二分即可。
其他的就是普通ETT的操作了。
复杂度
O(qlogn)
O
(
q
l
o
g
n
)
不用加哨兵…坑我半天不会把哨兵放进去。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
inline char gc(){
static char buf[1<<16],*S,*T;
if(T==S){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,m,in[N],out[N],dfn=0,fa[N<<1],c[N<<1][2],dep[N<<1],mn[N<<1],mx[N<<1],id[N<<1],rt=0,tag[N<<1],sz[N<<1],q[N<<1];
vector<int>Son[N];
inline void dfs(int x,int dept){
in[x]=++dfn;dep[dfn]=dept;id[dfn]=x;
for(int i=0;i<Son[x].size();++i) dfs(Son[x][i],dept+1);
out[x]=++dfn;dep[dfn]=dept;id[dfn]=x;
}
inline void update(int p){
int l=c[p][0],r=c[p][1];
sz[p]=sz[l]+sz[r]+1;
mx[p]=mn[p]=dep[p];
mx[p]=max(mx[p],max(mx[l],mx[r]));
mn[p]=min(mn[p],min(mn[l],mn[r]));
}
inline void doadd(int p,int val){
tag[p]+=val;dep[p]+=val;mn[p]+=val;mx[p]+=val;
}
inline void pushdown(int p){
if(!tag[p]) return;int l=c[p][0],r=c[p][1];
if(l) doadd(l,tag[p]);if(r) doadd(r,tag[p]);tag[p]=0;
}
inline void build(int &p,int l,int r){
int mid=l+r>>1;p=mid;
if(l<mid) build(c[p][0],l,mid-1),fa[c[p][0]]=p;
if(r>mid) build(c[p][1],mid+1,r),fa[c[p][1]]=p;update(p);
}
inline void rotate(int x,int &k){
int y=fa[x],z=fa[y],l=x==c[y][1],r=l^1;
if(y==k) k=x;
else c[z][y==c[z][1]]=x;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void splay(int x,int &k){
int top=0;q[++top]=x;
for(int xx=x;xx!=k;xx=fa[xx]) q[++top]=fa[xx];
while(top) pushdown(q[top--]);
while(x!=k){
int y=fa[x],z=fa[y];
if(y!=k){
if(x==c[y][1]^y==c[z][1]) rotate(x,k);
else rotate(y,k);
}rotate(x,k);
}
}
inline int findk(int p,int x){
int r=c[p][1];pushdown(p);
if(mn[r]<=x&&mx[r]>=x) return findk(r,x);
if(dep[p]==x) return id[p];
return findk(c[p][0],x);
}
inline int split(int x,int y){
splay(x,rt);splay(y,c[x][1]);return c[y][0];
}
inline int getpre(int x){
splay(x,rt);int res=c[x][0];
while(c[res][1]) res=c[res][1];
return res;
}
inline int getsucc(int x){
splay(x,rt);int res=c[x][1];
while(c[res][0]) res=c[res][0];
return res;
}
inline int del1(int x,int y){
int xx=getpre(x),yy=getsucc(y);
x=split(xx,yy);y=fa[x];c[y][0]=fa[x]=0;update(y);update(fa[y]);return x;
}
int main(){
// freopen("a.in","r",stdin);
n=read();m=read();mx[0]=0;mn[0]=inf;
for(int i=1;i<=n;++i){
int owo=read();
while(owo--) Son[i].push_back(read());
}dfs(1,0);build(rt,1,n<<1);
while(m--){
int op=read(),x=read();
if(op==3){
printf("%d\n",findk(rt,x));continue;
}int y=read();
if(op==1){
splay(in[x],rt);int xx=sz[c[in[x]][0]]+1,res=dep[in[x]];
splay(in[y],rt);int yy=sz[c[in[y]][0]]+1;res+=dep[in[y]];
if(xx>yy) swap(x,y);x=split(in[x],out[y]);res-=2*(mn[x]-1);
printf("%d\n",res);continue;
}splay(in[x],rt);int val=y-1;y=findk(c[rt][0],dep[in[x]]-y);
x=del1(in[x],out[x]);doadd(x,-val);int xx=getpre(out[y]);
splay(xx,rt);splay(out[y],c[rt][1]);c[out[y]][0]=x;fa[x]=out[y];
update(out[y]);update(rt);
}return 0;
}