[ZJOI2016]大森林

题目

洛谷
BZOJ
离线神仙题

做法

((0))区间生长((1))区间换点((2))单点查询

考虑仅一次区间换点((l,r,x)),区间生长:
就相当于换点后的生长的点在l时接在(x)上,到(r+1)时再接回去

有多次换点也同理,对每个换点新增一个虚点,建立一条虚链,每次生长则(link)到最近的前一个虚点

然后离线升序排树处理

My complete code

#include<bits/stdc++.h>
using namespace std;
typedef int LL;
inline LL Read(){
	LL x(0),f(1); char c=getchar();
	while(c<'0' || c>'9'){ if(c=='-')c=-1; c=getchar(); }
	while(c>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x*f;
}
const LL maxn=1e6;
LL n,m,nod,tot,now,num;
LL son[maxn][2],fa[maxn],size[maxn],w[maxn],r[maxn],ans[maxn],sta[maxn],pos[maxn],gl[maxn],gr[maxn];
inline bool Nroot(LL x){ return (son[fa[x]][0]==x || son[fa[x]][1]==x); }
inline void Update(LL x){ size[x]=size[son[x][0]]+size[son[x][1]]+w[x]; }
inline void Rotate(LL x){
	LL y(fa[x]),z(fa[y]),lz(son[y][1]==x);
	if(Nroot(y)) son[z][son[z][1]==y]=x; fa[x]=z;
	son[y][lz]=son[x][lz^1];
	if(son[y][lz]) fa[son[y][lz]]=y;
	son[x][lz^1]=y, fa[y]=x;
	Update(y), Update(x);
}
inline void Splay(LL x){
	while(Nroot(x)){
		LL y=fa[x];
		if(Nroot(y)){
			LL z(fa[y]);
			((son[y][1]==x)^(son[z][1]==y))?Rotate(y):Rotate(x);
		}Rotate(x);
	}
}
inline LL Access(LL x){
	LL lst(x);
	for(LL y=0;x;y=x,x=fa[x])
	    lst=x, Splay(x), son[x][1]=y, Update(x);
	return lst;
}
inline void Link(LL x,LL y){
	Splay(x), fa[x]=y;
}
inline void Cut(LL x){
	Access(x), Splay(x);
	son[x][0]=fa[son[x][0]]=0;
	Update(x);
}
inline LL Lca(LL x,LL y){
	Access(x); return Access(y);
}

struct node{
	LL tree,id,x,y;
}a[maxn];
inline bool cmp(node x,node y){
	if(!(x.tree ^ y.tree)) return x.id<y.id;
	return x.tree<y.tree;
}
int main(){
	n=Read(), m=Read();
	nod=w[1]=size[1]=pos[1]=gl[1]=1,gr[1]=n;
	Link(now=tot=2,1);
	for(LL i=1;i<=m;++i){
		LL opt(Read()),l(Read()),r(Read());
		if(opt==0){
			Link(pos[++nod]=++tot,now);
			w[tot]=size[tot]=1;
			gl[nod]=l, gr[nod]=r;
		}else if(opt==1){
			LL x; cin>>x;
			l=max(l,gl[x]), r=min(r,gr[x]);
			if(l>r) continue;
			Link(++tot,now);
			a[++num]=(node){l,i-m,tot,pos[x]};
			a[++num]=(node){r+1,i-m,tot,now};
			now=tot;
		}else{
			LL x(l),u(r),v(Read());
		    a[++num]=(node){x,++ans[0],pos[u],pos[v]};
		}
	}
	sort(a+1,a+1+num,cmp);
	for(LL i=1;i<=num;++i){
		if(a[i].id>0){
			LL x(a[i].x),y(a[i].y),lca(Lca(x,y));
			Access(x), Splay(x); ans[a[i].id]+=size[x];
			Access(y), Splay(y); ans[a[i].id]+=size[y];
			Access(lca), Splay(lca); ans[a[i].id]-=2*size[lca];
		}else
			Cut(a[i].x),Link(a[i].x,a[i].y);
	}
	for(LL i=1;i<=ans[0];++i) printf("%d
",ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/y2823774827y/p/10413059.html