bzoj 4573 大森林

  • 由于树上路径是唯一的,查询合法的两个点间路径长度显然与其他加点操作无关,所以可以离线处理,将所有的查询放在加点后.
  • 这样我们可以对每棵树都在上颗树的基础上处理好形态后,处理这颗树上的询问.
  • 考虑若没有操作 \(1\) ,则所有树都一模一样.那么两棵树的形态不同,一定是某一颗执行了操作 \(1\) ,另一个却没有.只需要在每个关键位置(修改开始或结束时)将原来生长点所有子树挂到新的生长点下.
  • 若暴力移动子树,当子树数目较大时就会很劣.可以对每个操作 \(1\) 建立一个虚点,将这个操作内挂上去的点都挂在虚点上,于是只需要移动虚点就可以了.注意将虚点 \(siz\) 设置为 \(0\) .
  • 查询答案时,使用 \(dep[x]+dep[y]-2*dep[lca]\) 计算,避免虚点造成的影响.
  • 直接用 \(split(x,y)\) 会出问题.因为你把路径抠出来之后不知道要不要减去 \(1\) .
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pii pair<int,int>
inline int read()
{
	int x=0;
	bool pos=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar())
		if(ch=='-')
			pos=0;
	for(;isdigit(ch);ch=getchar())
		x=x*10+ch-'0';
	return pos?x:-x;
}
const int MAXN=3e5+10;
struct query{
	int pos,op,x,y;
	bool operator < (const query &rhs) const
		{
			return pos==rhs.pos?op<rhs.op:pos<rhs.pos;
		}
}q[MAXN];
namespace LCT{
	int stk[MAXN],tp;
	int tot;
	struct node{
		int ch[2],fa;
		int rev;
		int siz,val;
		node()
			{
				fa=ch[0]=ch[1]=0;
				rev=0;
				siz=val=0;
			}
	}tree[MAXN];
	#define root tree[x]
	#define lson tree[root.ch[0]]
	#define rson tree[root.ch[1]]
	inline void pushup(int x)
		{
			root.siz=lson.siz+root.val+rson.siz;
		}
	void inverse(int x)
		{
			swap(root.ch[0],root.ch[1]);
			root.rev^=1;
		}
	void pushdown(int x)
		{
			if(root.rev)
				{
					if(root.ch[0])
						inverse(root.ch[0]);
					if(root.ch[1])
						inverse(root.ch[1]);
					root.rev=0;
				}
		}
	bool isroot(int x)
		{
			int y=root.fa;
			return tree[y].ch[0]!=x && tree[y].ch[1]!=x;
		}
	void rotate(int x)
		{
			int y=tree[x].fa,z=tree[y].fa;
			int k=tree[y].ch[1]==x;
			if(!isroot(y))
				tree[z].ch[tree[z].ch[1]==y]=x;
			tree[x].fa=z;
			tree[tree[x].ch[k^1]].fa=y;
			tree[y].ch[k]=tree[x].ch[k^1];
			tree[x].ch[k^1]=y;
			tree[y].fa=x;
			pushup(y);
			pushup(x);
		}
	void splay(int x)
		{
			tp=0;
			stk[++tp]=x;
			for(int pos=x;!isroot(pos);pos=tree[pos].fa)
				stk[++tp]=tree[pos].fa;
			while(tp)
				pushdown(stk[tp--]);
			while(!isroot(x))
				{
					int y=tree[x].fa,z=tree[y].fa;
					if(!isroot(y))
						(tree[y].ch[0]==x)^(tree[z].ch[0]==y)?rotate(x):rotate(y);
					rotate(x);
				}
			pushup(x);
		}
	int Access(int x)
		{
			int y;
			for(y=0;x;y=x,x=tree[x].fa)
				{
					splay(x);
					tree[x].ch[1]=y;
					pushup(x);
				}
			return y;
		}
	void makeroot(int x)
		{
			Access(x);
			splay(x);
			inverse(x);
		}
	int findroot(int x)
		{
			Access(x);
			splay(x);
			while(tree[x].ch[0])
				x=tree[x].ch[0];
			return x;
		}
	void split(int x,int y)
		{
			makeroot(x);
			Access(y);
			splay(y);
		}
	void Link(int x,int y)
		{
			makeroot(x);
			tree[x].fa=y;
		}
	void Cut(int x)
		{
			Access(x);
			splay(x);
			tree[tree[x].ch[0]].fa=0;
			tree[x].ch[0]=0;
			pushup(x);
		}
}
using namespace LCT;
int solve(int x,int y)
{
	int ans=0;
	Access(x);
	splay(x);
	ans+=tree[x].siz;
	int lca=Access(y);
	splay(y);
	ans+=tree[y].siz;
	Access(lca);
	splay(lca);
	ans-=2*tree[lca].siz;
	return ans;
}
void newnode(int v)
{
	int x=++tot;
	root.val=root.siz=v;
}
int n,m;
int last,id[MAXN],idd,cnt,L[MAXN],R[MAXN],qs;
inline void insq(int pos,int op,int x,int y)
{
	++cnt;
	q[cnt].pos=pos,q[cnt].op=op;
	q[cnt].x=x,q[cnt].y=y;
}
int ans[MAXN];
int main()
{
	tot=0;
	n=read(),m=read();
	newnode(1),idd=1,L[1]=1,R[1]=n,id[1]=1;
	newnode(0),last=2,Link(2,1);
	for(int i=1;i<=m;++i)
		{
			int type=read();
			if(type==0)
				{
					int l=read(),r=read();
					newnode(1);
					L[++idd]=l,R[idd]=r,id[idd]=tot;
					insq(1,i-m,tot,last);
				}
			else if(type==1)
				{
					int l=read(),r=read(),x=read();
					l=max(l,L[x]),r=min(r,R[x]);
					if(l<=r)
						{
							newnode(0);
							Link(tot,last);
							insq(l,i-m,tot,id[x]);
							insq(r+1,i-m,tot,last);
							last=tot;
						}
				}
			else
				{
					int x=read(),u=read(),v=read();
					insq(x,++qs,id[u],id[v]);
				}
		}
	sort(q+1,q+cnt+1);
	for(int i=1,j=1;i<=n;++i)
		{
			for(;j<=cnt && q[i].pos==i;++j)
				{
					if(q[j].op<=0)
						{
							Cut(q[j].x);
							Link(q[j].x,q[j].y);
						}
					else
						ans[q[j].op]=solve(q[j].x,q[j].y);
				}
		}
	for(int i=1;i<=qs;++i)
		printf("%d\n",ans[i]);
	return 0;
}

相关文章: