【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序

题目大意

​  Bob有一棵\(n\)个点的有根树,其中\(1\)号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:

​  \(1~x\):把点\(x\)到根节点的路径上所有的点染上一种没有用过的新颜色。

​  \(2~x~y\):求\(x\)\(y\)的路径的权值。

​  \(3~x~y\):在以\(x\)为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。

​  Bob一共会进行\(m\)次操作

  \(n,m\leq 100000\)

题解

​  注意到操作\(1\)就是\(access\)操作,可以用LCT维护。

​  设\(f_i=\)\(i\)到根的路径权值,则操作\(2\)的答案为\(f_x+f_y-2f_{lca}+1\)

​  如果只有操作\(1\)和操作\(2\)的话,就可以暴力往上跳,但是操作\(3\)就没那么好处理了。

​  所以我们可以用线段树+dfs序维护\(f_i\)

​  \(access\)切换虚实边时一棵子树的\(f\)全部\(+1\),另一棵子树的\(f\)全部\(-1\)

​  然后用倍增求LCA

  时间复杂度:\(O(n\log^2n)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int n,m;
namespace seg
{
	int s[4000010];
	int t[4000010];
	int n;
	void init()
	{
		n=0;
		memset(s,0,sizeof s);
		memset(t,0,sizeof t);
	}
	void at(int x,int v)
	{
		s[x]+=v;
		t[x]+=v;
	}
	void push(int x)
	{
		at(x*2,t[x]);
		at(x*2+1,t[x]);
		t[x]=0;
	}
	void add(int p,int l,int r,int v,int L,int R)
	{
		if(l<=L&&r>=R)
		{
			at(p,v);
			return;
		}
		if(t[p])
			push(p);
		int mid=(L+R)>>1;
		if(l<=mid)
			add(p*2,l,r,v,L,mid);
		if(r>mid)
			add(p*2+1,l,r,v,mid+1,R);
		s[p]=max(s[p*2],s[p*2+1]);
	}
	int query(int p,int l,int r,int L,int R)
	{
		if(l<=L&&r>=R)
			return s[p];
		if(t[p])
			push(p);
		int mid=(L+R)>>1;
		int res=0;
		if(l<=mid)
			res=max(res,query(p*2,l,r,L,mid));
		if(r>mid)
			res=max(res,query(p*2+1,l,r,mid+1,R));
		return res;
	}
}
namespace tree
{
	struct list
	{
		int v[200010];
		int t[200010];
		int h[100010];
		int n;
		list()
		{
			n=0;
			memset(h,0,sizeof h);
		}
		void add(int x,int y)
		{
			n++;
			v[n]=y;
			t[n]=h[x];
			h[x]=n;
		}
	};
	list l;
	int bg[100010];
	int ed[100010];
	int ti;
	int f[100010][20];
	int d[100010];
	void init()
	{
		memset(f,0,sizeof f);
		ti=0;
	}
	void dfs(int x,int fa,int dep)
	{
		bg[x]=++ti;
		f[x][0]=fa;
		d[x]=dep;
		int i;
		for(i=1;i<=19;i++)
			f[x][i]=f[f[x][i-1]][i-1];
		for(i=l.h[x];i;i=l.t[i])
			if(l.v[i]!=fa)
				dfs(l.v[i],x,dep+1);
		ed[x]=ti;
	}
	int getlca(int x,int y)
	{
		if(d[x]<d[y])
			swap(x,y);
		int i;
		for(i=19;i>=0;i--)
			if(d[f[x][i]]>=d[y])
				x=f[x][i];
		if(x==y)
			return x;
		for(i=19;i>=0;i--)
			if(f[x][i]!=f[y][i])
			{
				x=f[x][i];
				y=f[y][i];
			}
		return f[x][0];
	}
}
namespace lct
{
	int f[100010];
	int a[100010][2];
	void init()
	{
		memset(f,0,sizeof f);
		memset(a,0,sizeof a);
	}
	int root(int x)
	{
		return a[f[x]][0]!=x&&a[f[x]][1]!=x;
	}
	void rotate(int x)
	{
		if(root(x))
			return;
		int p=f[x];
		int q=f[p];
		int ps=(x==a[p][1]);
		int qs=(p==a[q][1]);
		int ch=a[x][ps^1];
		if(!root(p))
			a[q][qs]=x;
		a[x][ps^1]=p;
		a[p][ps]=ch;
		if(ch)
			f[ch]=p;
		f[p]=x;
		f[x]=q;
	}
	int splay(int x)
	{
		while(!root(x))
		{
			int p=f[x];
			if(!root(p))
				if((x==a[p][1])^(p==a[f[p]][1]))
					rotate(p);
				else
					rotate(x);
			rotate(x);
		}
	}
	void access(int x)
	{
		int t=0;
		int y=x,z;
		while(x)
		{
			splay(x);
			if(t)
			{
				while(a[t][0])
					t=a[t][0];
				splay(t);
				seg::add(1,tree::bg[t],tree::ed[t],-1,1,n);
			}
			z=a[x][1];
			a[x][1]=t;
			if(z)
			{
				while(a[z][0])
					z=a[z][0];
				splay(z);
				seg::add(1,tree::bg[z],tree::ed[z],1,1,n);
			}
			t=x;
			x=f[x];
		}
		splay(y);
	}
}
int main()
{
	lct::init();
	seg::init();
	tree::init();
//	freopen("bzoj4817.in","r",stdin);
//	freopen("bzoj4817.out","w",stdout);
	scanf("%d%d",&n,&m);
	int i,op,x,y,ans;
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		tree::l.add(x,y);
		tree::l.add(y,x);
	}
	tree::dfs(1,0,1);
	for(i=2;i<=n;i++)
		lct::f[i]=tree::f[i][0];
	for(i=1;i<=n;i++)
		seg::add(1,tree::bg[i],tree::bg[i],tree::d[i],1,n);
	for(i=1;i<=m;i++)
	{
		scanf("%d",&op);
		if(op==1)
		{
			scanf("%d",&x);
			lct::access(x);
		}
		else if(op==2)
		{
			scanf("%d%d",&x,&y);
			int lca=tree::getlca(x,y);
			ans=seg::query(1,tree::bg[x],tree::bg[x],1,n)+
					seg::query(1,tree::bg[y],tree::bg[y],1,n)-
					2*seg::query(1,tree::bg[lca],tree::bg[lca],1,n)+1;
			printf("%d\n",ans);
		}
		else
		{
			scanf("%d",&x);
			ans=seg::query(1,tree::bg[x],tree::ed[x],1,n);
			printf("%d\n",ans);
		}
	}
	return 0;
}
posted @ 2018-03-05 16:58  ywwyww  阅读(204)  评论(0编辑  收藏  举报