BZOJ4817[Sdoi2017]树点涂色——LCT+线段树

题目描述

Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路
径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
1 x:
把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y:
求x到y的路径的权值。
3 x
在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
Bob一共会进行m次操作

输入

第一行两个数n,m。
接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
接下来m行,表示操作,格式见题目描述
1<=n,m<=100000

输出

每当出现2,3操作,输出一行。
如果是2操作,输出一个数表示路径的权值
如果是3操作,输出一个数表示权值的最大值

样例输入

5 6
1 2
2 3
3 4
3 5
2 4 5
3 3
1 4
2 4 5
1 5
2 4 5

样例输出

3
4
2
2
 
我们将连续相同颜色的一条链看成一条重链,可以发现修改操作其实就是$LCT$里的$access$操作。
那么每个节点到根的权值就是这个点到根路径上的重链数。
考虑用线段树维护出每个点到根的权值,每次修改时假设路径上$x->fa$的边是轻边,$fa$的重儿子是$son$,那么就将$son$子树中所有点的答案$+1$,$x$子树中所有点答案$-1$,然后将$x$变为$fa$的重儿子。在$access$时完成子树修改操作即可。
对于查询$x$到$y$的路径权值,就是$v[x]+v[y]-2v[lca]+1$。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int c[100010][2];
int fa[100010];
int tag[400010];
int f[100010][18];
int dep[100010];
int mx[400010];
int dfn;
int tot;
int x,y;
int n,m;
int opt;
int head[100010];
int next[200010];
int to[200010];
int q[100010];
int s[100010];
int t[100010];
void add(int x,int y)
{
	next[++tot]=head[x];
	head[x]=tot;
	to[tot]=y;
}
void pushup(int rt)
{
	mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
}
void pushdown(int rt)
{
	if(tag[rt])
	{
		tag[rt<<1]+=tag[rt];
		tag[rt<<1|1]+=tag[rt];
		mx[rt<<1]+=tag[rt];
		mx[rt<<1|1]+=tag[rt];
		tag[rt]=0;
	}
}
void build(int rt,int l,int r)
{
	if(l==r)
	{
		mx[rt]=dep[q[l]];
		return ;
	}
	int mid=(l+r)>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	pushup(rt);
}
void change(int rt,int l,int r,int L,int R,int v)
{
	if(L<=l&&r<=R)
	{
		tag[rt]+=v;
		mx[rt]+=v;
		return ;
	}
	pushdown(rt);
	int mid=(l+r)>>1;
	if(L<=mid)
	{
		change(rt<<1,l,mid,L,R,v);
	}
	if(R>mid)
	{
		change(rt<<1|1,mid+1,r,L,R,v);
	}
	pushup(rt);
}
int query(int rt,int l,int r,int L,int R)
{
	if(L<=l&&r<=R)
	{
		return mx[rt];
	}
	pushdown(rt);
	int mid=(l+r)>>1;
	int res=0;
	if(L<=mid)
	{
		res=max(res,query(rt<<1,l,mid,L,R));
	}
	if(R>mid)
	{
		res=max(res,query(rt<<1|1,mid+1,r,L,R));
	}
	return res;
}
int ask(int rt,int l,int r,int k)
{
	if(l==r)
	{
		return mx[rt];
	}
	pushdown(rt);
	int mid=(l+r)>>1;
	if(k<=mid)
	{
		return ask(rt<<1,l,mid,k);
	}
	else
	{
		return ask(rt<<1|1,mid+1,r,k);
	}
}
bool is_root(int rt)
{
	return rt!=c[fa[rt]][0]&&rt!=c[fa[rt]][1];
}
bool get(int rt)
{
	return rt==c[fa[rt]][1];
}
void rotate(int rt)
{
	int x=fa[rt];
	int y=fa[x];
	int k=get(rt);
	if(!is_root(x))
	{
		c[y][get(x)]=rt;
	}
	c[x][k]=c[rt][k^1];
	fa[c[rt][k^1]]=x;
	c[rt][k^1]=x;
	fa[x]=rt;
	fa[rt]=y;
}
void splay(int rt)
{
	for(int x;!is_root(rt);rotate(rt))
	{
		if(!is_root(x=fa[rt]))
		{
			rotate(get(x)==get(rt)?x:rt);
		}
	}
}
void link(int x,int y)
{
	fa[x]=y;
}
int find(int rt)
{
	while(c[rt][0])
	{
		rt=c[rt][0];
	}
	return rt;
}
void access(int rt)
{
	for(int x=0;rt;x=rt,rt=fa[rt])
	{
		splay(rt);
		if(x)
		{
			int son=find(x);
			change(1,1,n,s[son],t[son],-1);
		}
		if(c[rt][1])
		{
			int son=find(c[rt][1]);
			change(1,1,n,s[son],t[son],1);
		}
		c[rt][1]=x;
	}
}
void dfs(int x)
{
	s[x]=++dfn;
	q[dfn]=x;
	for(int i=1;i<=17;i++)
	{
		f[x][i]=f[f[x][i-1]][i-1];
	}
	for(int i=head[x];i;i=next[i])
	{
		if(to[i]!=f[x][0])
		{
			f[to[i]][0]=x;
			link(to[i],x);
			dep[to[i]]=dep[x]+1;
			dfs(to[i]);
		}
	}
	t[x]=dfn;
}
int lca(int x,int y)
{
	if(dep[x]<dep[y])
	{
		swap(x,y);
	}
	int d=dep[x]-dep[y];
	for(int i=0;i<=17;i++)
	{
		if(d&(1<<i))
		{
			x=f[x][i];
		}
	}
	if(x==y)
	{
		return x;
	}
	for(int i=17;i>=0;i--)
	{
		if(f[x][i]!=f[y][i])
		{
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dep[1]=1;
	dfs(1);
	build(1,1,n);
	while(m--)
	{
		scanf("%d",&opt);
		if(opt==1)
		{
			scanf("%d",&x);
			access(x);
		}
		else if(opt==2)
		{
			scanf("%d%d",&x,&y);
			int anc=lca(x,y);
			int ans=ask(1,1,n,s[x])+ask(1,1,n,s[y])-2*ask(1,1,n,s[anc])+1;
			printf("%d\n",ans);
		}
		else
		{
			scanf("%d",&x);
			printf("%d\n",query(1,1,n,s[x],t[x]));
		}
	}
}
posted @ 2019-04-10 11:21  The_Virtuoso  阅读(230)  评论(0编辑  收藏  举报