巧妙的思路:显然分别维护每棵树是不可能的,时间空间都无法接受
所以换个想法,发现操作对于没换生长点时候的树都是一致的,所以可以直接改变一下策略,维护同一棵树
然后考虑修改生长点,可以离线操作,先保存所有操作和询问,加点就加到它最近新建的点就好了
Code:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=2e5+5;
namespace LCT{
int ls[N],rs[N],siz[N],s[N],fa[N];
inline int isrs(int x){return rs[fa[x]]==x;}
inline bool isroot(int x){
if(!x) return true;
return ls[fa[x]]!=x && rs[fa[x]]!=x;
}
inline void pushup(int x){siz[x]=siz[ls[x]]+siz[rs[x]]+s[x];}
inline void rotate(int x){
int y=fa[x],z=fa[y],b=(ls[y]==x?rs[x]:ls[x]);
if(z && !isroot(y)) (ls[z]==y?ls[z]:rs[z])=x;
fa[x]=z,fa[y]=x,b?fa[b]=y:0;
if(ls[y]==x) rs[x]=y,ls[y]=b;
else ls[x]=y,rs[y]=b;
pushup(y);pushup(x);
}
inline void splay(int x){
while(!isroot(x)){
while(!isroot(fa[x])){
if(isrs(fa[x])==isrs(x)) rotate(fa[x]);
else rotate(x);
}
rotate(x);
}
pushup(x);
}
inline int access(int x){int y=0;for(;x;y=x,x=fa[x]){splay(x);rs[x]=y;pushup(x);}return y;}
inline void link(int x,int y){splay(x);fa[x]=y;}
inline void cut(int x){access(x);splay(x);ls[x]=fa[ls[x]]=0;pushup(x);}
}
using namespace LCT;
int n,m,tot=0,cnt=0,now,cur=0;
int l[N],r[N],a[N],ans[N];
struct Q{int pos,op,x,y;}q[N<<2];
inline bool cmp(Q a,Q b){if(a.pos==b.pos) return a.op<b.op;return a.pos<b.pos;}
inline void ins(int x){s[tot+1]=siz[++tot]=x;}
int main(){
freopen("lx.in","r",stdin);
n=read();m=read();
ins(1);a[++cnt]=l[1]=1;r[1]=n;
ins(0);now=2;link(2,1);
int k,op,x,y;
for(int i=1;i<=m;i++){
op=read();
if(!op){
l[++cnt]=read();r[cnt]=read();
ins(1);a[cnt]=tot;
q[++cur]=(Q){1,i-m,tot,now};
}
else if(op==1){
x=read();y=read();k=read();
x=max(x,l[k]),y=min(y,r[k]);
if(x<=y){
ins(0);
if(x>1) link(tot,now);
q[++cur]=(Q){x,i-m,tot,a[k]};
q[++cur]=(Q){y+1,i-m,tot,now};now=tot;
}
}
else{
k=read();x=read();y=read();
q[++cur]=(Q){k,i,a[x],a[y]};
}
}
sort(q+1,q+cur+1,cmp);
memset(ans,-1,sizeof(ans));
for(int i=k=1;i<=n;i++){
for(;k<=cur && q[k].pos==i;k++){
if(q[k].op>0){
access(q[k].x);splay(q[k].x);ans[q[k].op]=siz[q[k].x];
x=access(q[k].y);splay(q[k].y);ans[q[k].op]+=siz[q[k].y];
access(x);splay(x);ans[q[k].op]-=siz[x]<<1;
}
else{cut(q[k].x);link(q[k].x,q[k].y);}
}
}
for(int i=1;i<=m;i++) if(ans[i]!=-1) cout<<ans[i]<<"\n";
return 0;
}