BZOJ4573 : [Zjoi2016]大森林
扫描线,从左到右依次处理每棵树。
用set按时间顺序维护影响了这棵树的所有操作,那么一个点的父亲就是它前面第一个操作1。
用Splay维护树的括号序列,那么两点间的距离就是括号数量减去匹配的括号个数。
添加或删除操作0就是单点换父亲,添加或删除操作1就是区间换父亲。可以通过添加虚点来实现区间换父亲操作。
时间复杂度$O(m\log m)$。
#include<cstdio> #include<algorithm> #include<set> using namespace std; const int N=200010; int n,m,i,j,op,x,y,z,cnt,L[N],R[N],q[N+5][2],ans[N],tot,ap[N]; int ga0[N],gd0[N],ga1[N],gd1[N],v[N<<1],nxt[N<<1],ed,G[N],V[N],W[N],NXT[N],cq; set<int>T0,T1; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} inline void add(int&x,int y){v[++ed]=y;nxt[ed]=x;x=ed;} inline void addq(int x,int y,int z){V[++cq]=y;W[cq]=z;NXT[cq]=G[x];G[x]=cq;} namespace DS{ const int M=N<<2; int son[M][2],f[M],size[M]; struct P{ int x,y; P(){x=y=0;} P(int _x,int _y){x=_x,y=_y;} inline P operator+(const P&v){return y>v.x?P(x,y-v.x+v.y):P(x+v.x-y,v.y);} inline void operator+=(const P&v){*this=*this+v;} }v[M],s[M]; inline void up(int x){ size[x]=size[son[x][0]]+size[son[x][1]]+1; s[x]=s[son[x][0]]+v[x]+s[son[x][1]]; } inline void rotate(int x){ int y=f[x],w=son[y][1]==x; son[y][w]=son[x][w^1]; if(son[x][w^1])f[son[x][w^1]]=y; if(f[y]){ int z=f[y]; if(son[z][0]==y)son[z][0]=x; if(son[z][1]==y)son[z][1]=x; } f[x]=f[y];son[x][w^1]=y;f[y]=x;up(y); } inline void splay(int x,int w){ while(f[x]!=w){ int y=f[x]; if(f[y]!=w){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);} rotate(x); } up(x); } void spilt(int x,int y){ splay(x,0);splay(y,x); f[son[x][0]]=f[son[y][1]]=0; if(son[x][0]&&son[y][1]){ int z=son[x][0]; while(son[z][1])z=son[z][1]; splay(z,0); son[z][1]=son[y][1]; f[son[y][1]]=z; up(z); } son[x][0]=son[y][1]=0; up(y);up(x); } inline int rank(int x){ splay(x,0); return size[son[x][0]]; } inline int ask(int x,int y){ splay(x,0);splay(y,x); P t=s[son[y][0]]+v[y]; return t.x+t.y; } inline void addright(int x,int y){ splay(x,0); x=son[x][1]; while(son[x][0])x=son[x][0]; son[x][0]=y; f[y]=x; up(x); splay(y,0); } inline void newnode(int o,int val,int z){ int x=o<<1,y=x|1; v[x]=P(0,val),v[y]=P(val,0); f[y]=x,son[x][1]=y; up(y);up(x); if(z)addright(z<<1,x); } } inline void add0(int x){ int y=q[x][1]; set<int>::iterator j=T0.lower_bound(x); j--; DS::spilt(y<<1,y<<1|1); if(q[*j][0])DS::addright(q[*j][1]<<1,y<<1); else DS::addright(q[*j][1]<<1|1,y<<1); T0.insert(x); } inline void del0(int x){ int y=q[x][1]; T0.erase(x); DS::spilt(y<<1,y<<1|1); } inline void add1(int x){ int y=q[x][1]; set<int>::iterator j=T0.lower_bound(x),k; if(*j<N&&!q[*j][0]){ k=T1.lower_bound(x); k=T0.find(*k); k--; DS::spilt(q[*j][1]<<1,q[*k][1]<<1|1); DS::addright(y<<1,q[*j][1]<<1); } T0.insert(x); T1.insert(x); } inline void del1(int x){ int y=q[x][1],pos; T0.erase(x); T1.erase(x); set<int>::iterator j=T0.lower_bound(x),k,o; if(*j<N&&!q[*j][0]){ k=T1.lower_bound(x); k=T0.find(*k); k--; o=T0.lower_bound(x); o--; DS::spilt(q[*j][1]<<1,q[*k][1]<<1|1); if(q[*o][0])DS::addright(q[*o][1]<<1,q[*j][1]<<1); else DS::addright(q[*o][1]<<1|1,q[*j][1]<<1); } } inline int query(int x,int y){ if(x==y)return 0; if(DS::rank(x<<1)>DS::rank(y<<1))swap(x,y); return DS::ask(x<<1,y<<1); } int main(){ read(n),read(m); L[cnt=1]=1,R[1]=n; q[0][0]=q[0][1]=1; for(i=1;i<=m+1;i++){ ap[i]=i; DS::newnode(i,1,0); } tot=m+1; for(i=1;i<=m;i++){ read(op),read(x),read(y); if(!op){ L[++cnt]=x;R[cnt]=y; q[i][1]=cnt; add(ga0[x],i),add(gd0[y],i); } if(op==1){ read(z); x=max(x,L[z]),y=min(y,R[z]); if(x>y)continue; DS::newnode(++tot,0,ap[z]); ap[z]=tot; q[i][0]=1,q[i][1]=tot; add(ga1[x],i),add(gd1[y],i); } if(op==2)read(z),addq(x,y,z); } T0.insert(0),T0.insert(N); T1.insert(0),T1.insert(N); for(i=1;i<=n;i++){ for(j=ga0[i];j;j=nxt[j])add0(v[j]); for(j=ga1[i];j;j=nxt[j])add1(v[j]); for(j=G[i];j;j=NXT[j])ans[j]=query(V[j],W[j]); for(j=gd0[i];j;j=nxt[j])del0(v[j]); for(j=gd1[i];j;j=nxt[j])del1(v[j]); } for(i=1;i<=cq;i++)printf("%d\n",ans[i]); return 0; }