【杂题】[BZOJ4573][UOJ#195]【ZJOI2016】大森林【数据结构】【LCT】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hzj1054689699/article/details/84790883

Description

小Y家里有一个大森林,里面有 n 棵树,编号从 1到 n 。一开始这些树都只是树苗,只有一个节点,标号为 1 。这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力。

小Y掌握了一种魔法,能让第 l 棵树到第 r棵树的生长节点长出一个子节点。同时她还能修改第 l 棵树到第 r棵树的生长节点。

她告诉了你她使用魔法的记录,你能不能管理她家的森林,并且回答她的询问呢?
第一行包含 2 个正整数 n,m,共有 n 棵树和 m 个操作。接下来 m 行,每行包含若干非负整数表示一个操作,操作格式为:
0 l r 表示将第 l 棵树到第 r 棵树的生长节点下面长出一个子节点,子节点的标号为上一个 0 号操作叶子标号加 1(例如,第一个 0 号操作产生的子节点标号为 2), l 到 r 之间的树长出的节点标号都相同。保证 1≤l≤r≤n 。
1 l r x 表示将第 l 棵树到第 r 棵树的生长节点改到标号为 x 的节点。对于 i (l≤i≤r)这棵树,如果标号 x 的点不在其中,那么这个操作对该树不产生影响。保证 1≤l≤r≤n , x 不超过当前所有树中节点最大的标号。
2 x u v 询问第 x 棵树中节点 u 到节点 v 点的距离,也就是在第 x 棵树中从节点 u 和节点 v 的最短路上边的 数量。保证1≤x≤n,这棵树中节点 u 和节点 v 存在。

N<=10^5, M<=2*10^5

Solution

首先可以确定的是,询问结果不会随着时间改变而改变,那么询问时间就不重要了。

另外对于一个更改生长节点操作,我们要将这个区间与更改到的节点出现的那次0操作区间取并

接下来我们将所有的0/1操作拆成左端点和右端点两个,从左到右扫

考虑LCT,一个加入0操作就是link,删除0操作就是cut,重点在于1操作,会将后面一堆点一起移动。

我们可以对于每一个1操作建一个虚点,记录所有的0操作前最晚的1操作是什么。一开始所有的1操作虚点连向它前一个1操作的虚点,当加入0操作就将这个点连向前面最晚的一个虚点。加入1操作就相应的将虚点原本连向前一个1操作的边删掉,连到对应点去,删除1操作就是一个逆过程。

注意可能出现一种情况是查询路径时可能虚点是LCA,这样就少算了1,因此我们要将边转点,后面的实点连向前面的虚点边权为1,虚点连虚点以及虚点连向前面的生长节点的边权为0。

时间复杂度O(m log n)

Code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 600005
using namespace std;
struct LCT
{
	int fn[N],pr[N],sm[N],t[N][2],f[N],d[N],r[N],n1;
	bool bz[N];
	void hb(int p,int x,int y)
	{
		if(x&&p>-1) t[x][p]=y;
		if(y) f[y]=x,fn[y]=p;
	}
	void up(int k)
	{
		sm[k]=sm[t[k][0]]+sm[t[k][1]]+pr[k];
	}
	void down(int k)
	{
		r[0]=0;
		if(r[k]) swap(t[k][0],t[k][1]),fn[t[k][0]]=0,fn[t[k][1]]=1,fn[0]=-1;
		if(t[k][0]) r[t[k][0]]^=r[k];
		if(t[k][1]) r[t[k][1]]^=r[k];
		r[k]=0;	
	}
	void rot(int k)
	{
		int fa=f[k],p=fn[k];
		hb(p,fa,t[k][1-p]);
		hb(fn[fa],f[fa],k);
		hb(1-p,k,fa);
		up(fa),up(k),up(f[k]);
	}
	void splay(int k,int x)
	{
		d[d[0]=1]=k;
		while(f[d[d[0]]]!=x&&fn[d[d[0]]]!=-1&&f[d[d[0]]]!=0) d[++d[0]]=f[d[d[0]-1]];
		fod(i,d[0],1) down(d[i]);
		while(f[k]!=x&&fn[k]!=-1&&f[k]!=0)
		{
			if(f[f[k]]==x||fn[f[k]]==-1||f[k]==0) rot(k);
			else if(fn[k]==fn[f[k]]) rot(f[k]),rot(k);
			else rot(k),rot(k);
		}
	}
	void access(int k)
	{
		int p=k;splay(k,0);
		fn[t[k][1]]=-1,t[k][1]=0,up(k);
		while(f[k]!=0)
		{
			splay(f[k],0);
			fn[t[f[k]][1]]=-1,hb(1,f[k],k);
			k=f[k],up(k);		
		}
		splay(p,0);
	}
	void make(int k)
	{
		access(k),r[k]^=1;
	}
	void link(int x,int y)
	{
		make(x),access(y);
		f[x]=y,fn[x]=-1;
	}
	void cut(int x,int y)
	{
		make(x),access(y);
		splay(x,0),splay(y,x);
		f[t[x][1]]=f[t[y][0]]=0;
		t[x][1]=t[y][0]=0;
		fn[y]=-1,f[y]=0; 
		access(y);
	}
	void lk(int x,int y,int p)
	{
		n1++;
		pr[n1]=p;
		link(x,n1),link(y,n1);
	}
}T;
struct node
{
	int x,p,u,v,w;
	friend bool operator <(node x,node y)
	{
		return (x.x<y.x)||(x.x==y.x&&y.p==2);
	}
}op[N];
int n,m,fr[N],ans[N],nq,lt[N][2];
int main()
{
	cin>>n>>m;
	int num=1,qs=0,ls=m+1;
	lt[1][0]=1,lt[1][1]=n;
	fo(i,2,m) lt[i][0]=lt[i][1]=n+1;
	fo(i,1,m)
	{
		int p,l,r,x;
		scanf("%d%d%d",&p,&l,&r);
		if(p==0)
		{
			fr[++num]=ls;
			op[++nq]={l,p,num,1,i};
			op[++nq]={r+1,p,num,-1,i};
			lt[num][0]=l,lt[num][1]=r;
		}
		else if(p==1)
		{
			scanf("%d",&x);
			l=max(l,lt[x][0]),r=min(r,lt[x][1]);
			if(l<=r)
			{
				T.pr[++ls]=0;
				T.link(ls-1,ls);
				op[++nq]={l,p,x,1,ls};
				op[++nq]={r+1,p,x,-1,ls};
			}
		}
		else
		{
			scanf("%d",&x);
			op[++nq]={l,p,r,x,++qs};
		}
	} 
	T.n1=ls;
	sort(op+1,op+nq+1);
	int j=1;
	T.link(1,m+1);
	fo(i,1,n)
	{
		while(j<=nq&&op[j].x<=i)
		{
			if(op[j].p==0) 
			{
				if(op[j].v==1) T.lk(fr[op[j].u],op[j].u,1);
				else T.cut(fr[op[j].u],op[j].u);
			}
			else if(op[j].p==1)
			{
				if(op[j].v==1) T.cut(op[j].w-1,op[j].w),T.link(op[j].u,op[j].w);
				else T.cut(op[j].u,op[j].w),T.link(op[j].w-1,op[j].w);
			}
			else
			{
				T.make(op[j].u),T.access(op[j].v);
				ans[op[j].w]=T.sm[op[j].v];
			}
			j++;
		}
	}
	fo(i,1,qs) printf("%d\n",ans[i]);
}

猜你喜欢

转载自blog.csdn.net/hzj1054689699/article/details/84790883
今日推荐