【bzoj4753】【uoj#195】【LOJ2092】【ZJOI2016】大森林

显然0操作的时候可以当做所有树都加了这么一个点(但是后面挂到这个点的1操作的区间要对这个区间取min),这样0和2操作都跟时间没有关系了。
可以对每个1操作建一个虚点,点权为0,然后从它到下一个1操作间的所有0操作都可以连到这个虚点。虚点先默认连向上一次1操作,一边从左到右扫一边把1操作连到对应的点或者把它连回上一个1操作,这样就可以用LCT维护出所有位置的树。
但是这样查询的时候是会出锅的。查两个点距离的时候,如果我们直接split,可能会把一个虚点当做lca,实际上还要走到上面第一个实点。
其实有根树的LCT上是可以求lca的,access的时候返回最后转到根的那个点,求的时候access(x),然后access(y)返回的点就是lca(因为lca肯定是最后一个被access的点)。
我代码写得真是太shit了。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mxn=262144;
int rd(){
	int x=0;
	char c=getchar();
	for (;c<48||c>57;c=getchar());
	for (;c>47&&c<58;x=x*10+c-48,c=getchar());
	return x;
}
struct nd{
	int sum;
	bool cnt,tag;
	nd *ls,*rs,*fa;
}pool[mxn],*tpp=pool,*id[mxn],*stk[mxn];
bool noroot(nd *i){
	return i->fa&&(i->fa->ls==i||i->fa->rs==i);
}
void pushup(nd *i){
	i->sum=i->cnt;
	if (i->ls) i->sum+=i->ls->sum;
	if (i->rs) i->sum+=i->rs->sum;
}
void reverse(nd *i){
	if (i) swap(i->ls,i->rs),i->tag^=1;
}
void pushdown(nd *i){
	if (i->tag) i->tag=0,reverse(i->ls),reverse(i->rs);
}
void rotate(nd *i){
	nd *f=i->fa,*s;
	if (noroot(f))
		if (f->fa->ls==f) f->fa->ls=i;
		else f->fa->rs=i;
	else;
	i->fa=f->fa,f->fa=i;
	if (f->ls==i) f->ls=s=i->rs,i->rs=f;
	else f->rs=s=i->ls,i->ls=f;
	if (s) s->fa=f;
	pushup(f),pushup(i);
}
void splay(nd *x,int tp=1){
	stk[1]=x;
	for (nd *y=x;noroot(y);stk[++tp]=y=y->fa);
	for (;tp;pushdown(stk[tp--]));
	for (nd *y;noroot(x);rotate(x))
		if (noroot(y=x->fa)) rotate((y->ls==x)^(y->fa->ls==y)?x:y);
}
nd *access(nd *x,nd *y=0){
	for (;x;x=(y=x)->fa)
		splay(x),x->rs=y,pushup(x);
	return y;
}
void link(nd *x,nd *y){
	splay(x),x->fa=y;
}
void cut(nd *x,nd *y){
	access(y),splay(y),splay(x),x->fa=0;
}
int n,m,q,tot,k,lb[mxn],rb[mxn],cr[mxn],ty[mxn],ans[mxn];
struct node{
	int id,pos,x,y,z;
}a[mxn];
bool operator<(const node x,const node y){
	return x.pos<y.pos||(x.pos==y.pos&&x.id<y.id);
}
int main()
{
	m=rd(),q=rd();
	lb[1]=1,rb[1]=m,id[1]=++tpp;
	n=1,m=0;
	tpp->sum=tpp->cnt=1;
	for (int i=1;i<=q;++i){
		int typ=rd();
		if (!typ){
			id[++n]=++tpp,tpp->sum=tpp->cnt=1;
			lb[n]=rd(),rb[n]=rd();
		}
		else if (typ==1)
			a[++tot].x=rd(),a[tot].y=rd(),a[tot].pos=rd(),cr[++k]=n;
		else ++tot,a[tot]=(node){++m,rd(),rd(),rd(),0},ty[tot]=1;
	}
	cr[k+1]=n,k=0;
	q=tot;
	for (int i=2;i<=cr[1];++i) link(id[i],id[1]);
	for (int i=1,lst=1,cur=cr[1]+1;i<=tot;++i)
		if (!ty[i]){
			int l=max(a[i].x,lb[a[i].pos]),r=min(a[i].y,rb[a[i].pos]);
			node x=(node){(l>r)*(m+1),l,++n,lst,a[i].pos};
			a[i]=x;
			a[++q]=(node){(l>r)*(m+1),r+1,n,a[i].z,lst};
			id[n]=++tpp,link(id[n],id[lst]),lst=n;
			for (++k;cur<=cr[k+1];++cur) link(id[cur],id[n]);
		}
	sort(a+1,a+q+1);
	tot=0;
	for (int i=1;i<=q;++i)
		if (!a[i].id)
			cut(id[a[i].x],id[a[i].y]),link(id[a[i].x],id[a[i].z]);
		else if (a[i].id<=m){
			access(id[a[i].x]),splay(id[1]),ans[a[i].id]+=id[1]->sum;
			nd *z=access(id[a[i].y]);splay(id[1]),ans[a[i].id]+=id[1]->sum;
			access(z),splay(id[1]),ans[a[i].id]-=2*id[1]->sum;
			if (++tot==m) break;
		}
	for (int i=1;i<=m;++i) printf("%d
",ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/zzqtxdy/p/11488107.html