传送门:bzoj4573
题解
观察到操作中没有撤回,对于每颗树,节点一旦出现位置就固定了,所以考虑离线操作,将操作变为左右端点的加入和撤回,扫到对应的树时回答询问。
问题的关键在于:然每棵树对应着不同的生长节点,但每次新增叶子节点的操作完全是等价的,所以考虑对于每一次1操作新建一个值为0的虚点,将与下一次1操作间隔中的新增节点都连在这个虚点上。而1操作就转变成了在 [ l , r ] [l,r] [l,r]区间内将虚点连在对应的节点下, [ 1 , l − 1 ] ∪ [ r + 1 , n ] [1,l-1]\cup[r+1,n] [1,l−1]∪[r+1,n]区间内将虚点连在上一个虚点下。
记录一下每个实点对应标号和合法区间即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m,cur,id[N],lf[N],rt[N],tot;
int ans[N<<1];
inline char gc()
{
static char buf[N];
static int p1=0,p2=0;
if(p1==p2) p1=0,p2=fread(buf,1,N,stdin);
if(p1==p2) return EOF;
return buf[p1++];
}
char cp;
inline void rd(int &x)
{
cp=gc();x=0;
for(;!isdigit(cp);cp=gc());
for(;isdigit(cp);cp=gc()) x=(x<<3)+(x<<1)+(cp^48);
}
struct qr{
int pos,typ,x,y;
bool operator<(const qr&ky)const{
if(pos!=ky.pos) return pos<ky.pos;
return typ<ky.typ;
}
}q[N<<1];
namespace LCT{
#define F(x) t[(x)].fa
#define lc(x) t[(x)].ch[0]
#define rc(x) t[(x)].ch[1]
#define pushup(x) t[(x)].ss=t[lc((x))].ss+t[rc((x))].ss+t[(x)].v
#define notrt(x) (F((x))&&(lc(F((x)))==(x) || rc(F((x)))==(x)))
int cnt;
struct node{
int ch[2],fa,v,ss;
inline void itia(){v=ss=1;}
}t[N<<1];
inline void rotate(int x)
{
int y=F(x),z=F(y),pr=(rc(y)==x);
t[y].ch[pr]=t[x].ch[pr^1];F(t[y].ch[pr])=y;
F(x)=z;if(notrt(y)) t[z].ch[rc(z)==y]=x;
F(y)=x;t[x].ch[pr^1]=y;
pushup(y);
}
inline void splay(int x)
{
int y,z;
for(;notrt(x);rotate(x)){
y=F(x);z=F(y);
if(notrt(y))
((rc(y)==x)^(rc(z)==y))?rotate(x):rotate(y);
}
pushup(x);
}
inline void lk(int x,int y){splay(x);F(x)=y;}
inline int access(int x)
{
splay(x);rc(x)=0;pushup(x);
for(;F(x);x=F(x)){
splay(F(x));rc(F(x))=x;pushup(x);
}
return x;
}
inline void cutt(int x)
{
access(x);splay(x);
F(lc(x))=0;lc(x)=0;pushup(x);
}
}
using namespace LCT;
int main(){
int i,j,op,x,y,z;
rd(n);rd(m);
id[1]=++cnt;t[cnt].itia();
lf[1]=1;rt[1]=n;
cur=++cnt;lk(2,1);n=1;
for(i=1;i<=m;++i){
rd(op);rd(x);rd(y);
if(!op){
id[++n]=++cnt;t[cnt].itia();
lf[n]=x;rt[n]=y;
q[++tot]=(qr){0,-1,cnt,cur};
}else if(op==1){
rd(z);x=max(x,lf[z]);y=min(y,rt[z]);
if(x<=y){
cnt++;
if(x>1) lk(cnt,cur);
q[++tot]=(qr){x,0,cnt,id[z]};
q[++tot]=(qr){y+1,0,cnt,cur};
cur=cnt;
}
}else{rd(z);q[++tot]=(qr){x,i,id[y],id[z]};}
}
sort(q+1,q+tot+1);
memset(ans,0xff,sizeof(ans));
for(i=j=1;i<=tot;i=j){
for(;j<=tot && q[j].pos==q[i].pos;++j){
if(q[j].typ>0){
x=q[j].x;y=q[j].y;z=q[j].typ;
access(x);splay(x);ans[z]=t[x].ss;
x=access(y);splay(y);ans[z]+=t[y].ss;
access(x);splay(x);ans[z]-=(t[x].ss<<1);
}else{
cutt(q[j].x);lk(q[j].x,q[j].y);
}
}
}
for(i=1;i<=tot;++i) if(ans[i]!=-1) printf("%d\n",ans[i]);
return 0;
}