Description
给定 (n) 个树,每个树初始的生长点为 (1),需要支持以下操作
-
生长:让 ([l,r]) 中的树长出来一个其生长点下面的点
-
修改:更改生长点
-
查询:求某棵树上两点距离
(n,Qle 10^5)
Solution
考虑题设可以把它们都离线之后统一处理,那么 (trivial) 地用扫描线处理操作
也就是每棵树先长出来最终形态再回答询问
对于生长一个节点,直接差分,最后统一做即可
而对于更换生长点,考虑建立若干虚点表示操作,但是没有点权(真正生长出来的点有点权,为了求 (dis) )
具体而言,一开始求最终方案的时候
修改 (l,r) 的生长点,先对存在 (x) 号点的区间取交集
之后让新点和原来的生长点连边,再和新的生长点连边
在最后的统一处理中把虚点切掉/连上即可
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define For(i,a,b) for(register int i=a;i<=b;++i)
#define Down(i,a,b) for(register int i=a;i>=b;i--)
#define reg register
namespace yspm{
inline int read(){
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int N=4e5+10;
int fa[N],rs[N],ls[N],sum[N],v[N];
inline int min(int x,int y){return x<y?x:y;}
inline int max(int x,int y){return x>y?x:y;}
inline void swap(int &x,int &y){int t=x; x=y; y=t; return ;}
inline bool isroot(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
inline void push_up(int x){sum[x]=sum[ls[x]]+sum[rs[x]]+v[x]; return ;}
inline void rotate(int x){
int y=fa[x],z=fa[y]; if(!isroot(y)) if(ls[z]==y) ls[z]=x; else rs[z]=x;
if(ls[y]==x) ls[y]=rs[x],fa[rs[x]]=y,rs[x]=y;
else rs[y]=ls[x],fa[ls[x]]=y,ls[x]=y;
fa[x]=z; fa[y]=x; return push_up(y),push_up(x);
}
inline void splay(int x){
while(!isroot(x)){
int y=fa[x],z=fa[y]; if(!isroot(y)) rotate((ls[y]==x)^(ls[z]==y)?x:y);
rotate(x);
} return push_up(x);
}
struct query{
int pos,id,x,y;
bool operator<(const query &a)const{return pos^a.pos?pos<a.pos:id<a.id;}
}q[N];
inline int access(int x){int y=0; for(;x;x=fa[y=x]) splay(x),rs[x]=y,push_up(x); return y;}
inline void cut(int x){access(x); splay(x); ls[x]=fa[ls[x]]=0; push_up(x); return ;}
inline void link(int x,int y){splay(x),fa[x]=y; return ;}
int L[N],R[N],nd[N],ctq,n,Q,num,st,pos,cnt,ans[N];
signed main(){
//freopen("1.in","r",stdin);
n=read(); Q=read(); L[1]=1,R[1]=n; num=v[1]=sum[1]=nd[1]=1; link(pos=st=2,1);
for(reg int i=1,x,opt,l,r;i<=Q;++i){
opt=read(),l=read(),r=read();
if(opt==0) link(nd[++num]=++pos,st),v[pos]=sum[pos]=1,L[num]=l,R[num]=r;
else if(opt==1){
x=read(),l=max(l,L[x]); r=min(r,R[x]); if(r<l) continue;
link(++pos,st); q[++cnt]=(query){l,i-Q,pos,nd[x]}; q[++cnt]=(query){r+1,i-Q,pos,st};
st=pos;
}else x=read(),q[++cnt]=(query){l,++ctq,nd[r],nd[x]};
}
sort(q+1,q+cnt+1);
for(reg int lca,i=1,res;i<=cnt;++i){
if(q[i].id>0){
res=0; access(q[i].x); splay(q[i].x); res+=sum[q[i].x];
lca=access(q[i].y); splay(q[i].y); res+=sum[q[i].y];
access(lca); splay(lca); ans[q[i].id]=res-2*sum[lca];
}else cut(q[i].x),link(q[i].x,q[i].y);
}
for(reg int i=1;i<=ctq;++i) printf("%lld
",ans[i]);
return 0;
}
}
signed main(){return yspm::main();}