4573: [Zjoi2016]大森林
又是一道神仙毒瘤题,我们可以将询问放到最后,这样就可以用扫描线搞了,对于第 i i i棵树,可以从第 i − 1 i-1 i−1棵树继承过来,所以我们可以建一棵LCT来维护。
但是这题的难点是1操作,对于1操作我们建虚点,让0操作的点连向输入时间最近的虚点,然后虚点之间连边 ( i , i − 1 ) (i,i-1) (i,i−1)。每次遇到1操作,断开这个操作原来的虚边,连向实际的节点。但是谁想得到啊!!!
调试调到自闭,最后发现continue跳过了我对答案负的初值QAQ,不过LCT尽然一遍写对了。
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=600005;
int q,L,P1,P2,n,m,cnt,LT[MAXN],RT[MAXN],Ans[MAXN],Tim,Top,a[MAXN];
struct LCT{
int rev[MAXN],Fa[MAXN],Son[MAXN][2],Siz[MAXN];
bool IsRoot(int rt){return Son[Fa[rt]][0]!=rt&&Son[Fa[rt]][1]!=rt;}
bool Get(int rt){return Son[Fa[rt]][1]==rt;}
void PushUp(int rt){Siz[rt]=Siz[Son[rt][0]]+Siz[Son[rt][1]]+a[rt];}
void PushDown(int rt){
if(!rev[rt]) return;
rev[rt]^=1,rev[Son[rt][0]]^=1,rev[Son[rt][1]]^=1;
swap(Son[rt][0],Son[rt][1]);
}
void Rotate(int x){
int fa=Fa[x],L=Get(x);
if(!IsRoot(fa)) Son[Fa[fa]][Get(fa)]=x;
Fa[x]=Fa[fa],Fa[Son[x][L^1]]=fa,Fa[fa]=x;
Son[fa][L]=Son[x][L^1],Son[x][L^1]=fa;
PushUp(fa),PushUp(x);
}
void DFS(int x){if(!IsRoot(x)) DFS(Fa[x]);PushDown(x);}
void Splay(int x){for(DFS(x);!IsRoot(x);Rotate(x)) if(!IsRoot(Fa[x])) Rotate(Get(Fa[x])==Get(x)?Fa[x]:x);}
void Access(int x){for(int lst=0;x;lst=x,x=Fa[x]) Splay(x),Son[x][1]=lst,PushUp(x);}
void MakeRoot(int x){Access(x),Splay(x),rev[x]^=1;}
void Link(int x,int y){MakeRoot(x),Fa[x]=y;}
void Cut(int x,int y){MakeRoot(x),Access(y),Splay(y),Fa[x]=Son[y][0]=0,PushUp(y);}
int Ask(int x,int y){MakeRoot(x),Access(y),Splay(y);return Siz[y];}
}T;
struct Seg{
int p,opt,u,v,t;
bool operator <(const Seg b)const{return p<b.p||(p==b.p&&opt<b.opt);}
}Line[MAXN];
#include<cctype>
int read(){
int ret=0;char ch=getchar();bool f=1;
for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
for(; isdigit(ch);ch=getchar()) ret=ret*10+ch-48;
return f?ret:-ret;
}
int main(){
n=read(),m=read();
Tim=1;LT[1]=1,RT[1]=n;
for(int i=1;i<=m;i++){
Ans[i]=-1;
int Type=read();
if(Type==0){
int L=read(),R=read();LT[++Tim]=L,RT[Tim]=R;
Line[++Top]=(Seg){L,1,Tim,0,i},Line[++Top]=(Seg){R,5,Tim,0,i};
}else
if(Type==1){
int L=read(),R=read(),k=read();if(k>Tim) continue;
L=max(LT[k],L),R=min(RT[k],R);if(L>R) continue;
Line[++Top]=(Seg){L,2,0,k,i},Line[++Top]=(Seg){R,4,0,k,i};
}else Line[++Top]=(Seg){read(),3,read(),read(),i};
}
cnt=Tim+1;
for(int i=1;i<=Top;i++){
if(Line[i].opt==1) Line[i].v=cnt;else
if(Line[i].opt==2) Line[i].u=++cnt;else
if(Line[i].opt==4) Line[i].u=cnt;else
if(Line[i].opt==5) Line[i].v=cnt;
}
sort(Line+1,Line+1+Top);T.Link(1,Tim+1);
for(int i=Tim+2;i<=cnt;i++) T.Link(i-1,i);
for(int i=1;i<=Tim;i++) a[i+cnt]=T.Siz[i+cnt]=1;
for(int j=1;j<=Top;j++)
if(Line[j].p){
if(Line[j].opt==1) T.Link(Line[j].u,Line[j].u+cnt),T.Link(Line[j].u+cnt,Line[j].v);else
if(Line[j].opt==2) T.Cut(Line[j].u,Line[j].u-1),T.Link(Line[j].v,Line[j].u);else
if(Line[j].opt==3) Ans[Line[j].t]=T.Ask(Line[j].u,Line[j].v);else
if(Line[j].opt==4) T.Cut(Line[j].v,Line[j].u),T.Link(Line[j].u,Line[j].u-1);else
if(Line[j].opt==5) T.Cut(Line[j].u,Line[j].u+cnt),T.Cut(Line[j].u+cnt,Line[j].v);
}
for(int i=1;i<=m;i++) if(Ans[i]!=-1) printf("%d\n",Ans[i]);
return 0;
}