题解:
好题啊。
我们直接从左往右离线做。
问题就变成了动态插入,删除0,1操作。
明显插入删除1操作都是将连续的一段0换父亲, 我们可以建虚点来维护, 每个连续段的虚点彼此相连,插入则改变与前面的连接即可。
用LCT维护,时间复杂度 O(nlogn) O ( n log n ) 。
#include <bits/stdc++.h>
using namespace std;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN], *ib, *ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0, f=1;
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
inline void W(int x) {
static int buf[50];
if(!x) {putchar('0'); return;}
if(x<0) {putchar('-'); x=-x;}
while(x) {buf[++buf[0]]=x%10; x/=10;}
while(buf[0]) {putchar(buf[buf[0]--]+'0');}
}
const int N=2e5+50;
int n, m, cnt=1, tot;
int L[N], R[N];
struct node {
node *lc, *rc, *fa;
int v, sum;
inline void upt() {
sum=lc->sum+rc->sum+v;
}
}Pool[N], *pool=Pool, *null=Pool, *vir_fa[N], *ori_fa[N], *pos[N], *pos2[N], *pre[N], *lst;
inline node* newnode(int v) {
node *t=++pool;
t->lc=t->rc=t->fa=null;
t->v=t->sum=v;
return t;
}
inline bool isroot(node *x) {return x->fa->lc!=x && x->fa->rc!=x; }
inline bool which(node *x) {return x->fa->lc==x;}
inline void rotate(node *x) {
node *y=x->fa, *z=y->fa;
if(!isroot(y)) ((z->lc==y)?z->lc:z->rc)=x;
x->fa=z; y->fa=x;
if(y->lc==x) {
node *b=x->rc;
x->rc=y; y->lc=b;
if(b!=null) b->fa=y;
} else {
node *b=x->lc;
x->lc=y; y->rc=b;
if(b!=null) b->fa=y;
} y->upt(); x->upt();
}
inline void splay(node *x) {
while(!isroot(x)) {
node *y=x->fa;
if(!isroot(y)) {
if(which(x)==which(y)) rotate(y);
else rotate(x);
} rotate(x);
}
}
inline node* access(node *x) {
node *t=null;
for(node *y=null; x!=null; y=x, x=x->fa) {
t=x; splay(x);
x->rc=y; x->upt();
}
return t;
}
inline void link(node *x, node *f) {
splay(x); x->fa=f;
}
inline void cut(node *x, node *f) {
access(f);
splay(x);
x->fa=null;
}
struct data { int op, x, id; };
vector <data> query_s[N];
int ans[N];
int main() {
memset(ans, -1 ,sizeof(ans));
pos[1]=newnode(1);
lst=pos[1];
n=rd(), m=rd();
L[1]=1; R[1]=n;
for(int i=1; i<=m; i++) {
int op=rd();
if(!op) {
int l=rd(), r=rd(), x=++cnt;
vir_fa[x]=lst;
pos[x]=newnode(1);
L[x]=l, R[x]=r;
query_s[l].push_back((data){1,x,i});
query_s[r+1].push_back((data){-1,x,i});
} else if(op==1){
int l=rd(), r=rd(), x=rd();
l=max(l, L[x]), r=min(r, R[x]);
if(l>r) continue;
++tot;
pos2[tot]=newnode(0);
pre[tot]=lst;
lst=pos2[tot];
ori_fa[tot]=pos[x];
query_s[l].push_back((data){2,tot,i});
query_s[r+1].push_back((data){-2,tot,i});
} else {
int p=rd(), u=rd(), v=rd();
query_s[p].push_back((data){u+3,v+3,i});
}
}
for(int i=1; i<=tot; i++)
link(pos2[i], pre[i]);
for(int i=1; i<=n; i++) {
for(int e=0; e<query_s[i].size(); e++) {
data u=query_s[i][e];
if(u.op>2) {
int x=u.op-3, y=u.x-3;
access(pos[y]);
int v=(splay(pos[y]), pos[y]->sum);
node *t=access(pos[x]);
v+=(splay(pos[x]), pos[x]->sum);
v-=(access(t), splay(t), 2*t->sum);
ans[u.id]=v;
} else if(u.op==1) {
link(pos[u.x], vir_fa[u.x]);
} else if(u.op==-1) {
cut(pos[u.x], vir_fa[u.x]);
} else if(u.op==2) {
cut(pos2[u.x], pre[u.x]);
link(pos2[u.x], ori_fa[u.x]);
} else {
cut(pos2[u.x], ori_fa[u.x]);
link(pos2[u.x], pre[u.x]);
}
}
}
for(int i=1; i<=m; i++) {
if(~ans[i]) W(ans[i]), putchar('\n');
}
}