SPOJ16580 BZOJ3639 QTREE7 - Query on a tree VII LCT

题目链接

题意:
给你一个 n n n个点的树,每个点有点权和一个颜色,颜色是黑白之一。有 m m m次操作,每次有三种可能的操作,第一种是修改一个点的颜色,第二种是修改一个点的权值,第三个是给你一个 x x x,问所有到 x x x路径上颜色全相同点的最大权值。 n , m &lt; = 1 e 5 n,m&lt;=1e5 n,m<=1e5

题解:
和QTREE6差不多,但是这次是维护子树最大值。我们在之前的思路上进行改进。我们知道,用LCT维护虚子树的话,一般是要用set或者multiset来维护的。我们对每个点开一个multiset,在每个multiset里维护这个点的所有虚子树的子树最大值,在虚实子树切换的时候更改一下,也就是在link和access的时候要改变multiset里的元素。然后注意一下multiset是空集的时候。其他的就和QTREE6差不多,就不多说了。

代码:

#include <bits/stdc++.h>
using namespace std;

int n,m,hed[200010],cnt,col[200010],val[200010],fa[200010];
struct edge
{
	int to,next;
}a[400010];
struct LCT
{
	int f[200010],c[200010][2],val[200010],mx[200010];
	multiset<int> s[200010];
	inline int nroot(int x)
	{
		return c[f[x]][0]==x||c[f[x]][1]==x;
	} 
	inline void pushup(int x)
	{
		mx[x]=val[x];
		if(c[x][0])
		mx[x]=max(mx[x],mx[c[x][0]]);
		if(c[x][1])
		mx[x]=max(mx[x],mx[c[x][1]]);
		if(!s[x].empty())
		mx[x]=max(mx[x],(*(--s[x].end())));
	}
	inline void rotate(int x)
	{
		int y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
		if(nroot(y))
		c[z][c[z][1]==y]=x;
		c[x][!k]=y;
		c[y][k]=w;
		if(w)
		f[w]=y;
		f[y]=x;
		f[x]=z;
		pushup(y);
		pushup(x);
	}
	inline void splay(int x)
	{
		while(nroot(x))
		{
			int y=f[x],z=f[y];
			if(nroot(y))
			{
				if(c[z][1]==y^c[y][1]==x)
				rotate(x);
				else
				rotate(y);
			}
			rotate(x);
		}
		pushup(x);
	}
	inline void access(int x)
	{
		int y=0;
		while(x)
		{
			splay(x);
			if(y)
			s[x].erase(s[x].find(mx[y]));
			if(c[x][1])			
			s[x].insert(mx[c[x][1]]);
			c[x][1]=y;
			if(y)
			f[y]=x;
			pushup(x);
			y=x;
			x=f[x];
		}
	}
	inline void link(int x,int y)
	{
		access(x);
		splay(x);
		access(y);
		splay(y);
		f[x]=y;
		s[y].insert(mx[x]);
		pushup(y);
	}
	inline void cut(int x)
	{
		access(x);
		splay(x);
		f[c[x][0]]=0;
		c[x][0]=0;
	}
	inline int find(int x)
	{
		access(x);
		splay(x);
		while(c[x][0])
		x=c[x][0];
		return x;
	}
}b,w;
inline int read()
{
	int x=0,f=1;
	char s=getchar();
	while(s>'9'||s<'0')
	{
		if(s=='-')
		f=-1;
		s=getchar();
	}	
	while(s>='0'&&s<='9')
	{
		x=x*10+s-'0';
		s=getchar();
	}
	return x*f;
}
inline void add(int from,int to)
{
	a[++cnt].to=to;
	a[cnt].next=hed[from];
	hed[from]=cnt;
}
inline void dfs(int x)
{
	for(int i=hed[x];i;i=a[i].next)
	{
		int y=a[i].to;
		if(y==fa[x])
		continue;
		fa[y]=x;
		dfs(y);
	}
}
int main()
{
	n=read();
	for(int i=1;i<=n-1;++i)
	{
		int x=read(),y=read();
		add(x,y);
		add(y,x);
	}
	for(int i=1;i<=n;++i)
	col[i]=read();
	for(int i=1;i<=n;++i)
	val[i]=read();
	fa[1]=n+1;
	dfs(1);
	b.val[n+1]=-2e9;
	b.mx[n+1]=-2e9;
	w.val[n+1]=-2e9;
	w.mx[n+1]=-2e9;
	for(int i=1;i<=n;++i)
	{
		b.val[i]=val[i];
		w.val[i]=val[i];
		b.mx[i]=val[i];
		w.mx[i]=val[i];
	}
	for(int i=1;i<=n;++i)
	{
		
		if(col[i])
		b.link(i,fa[i]);
		else
		w.link(i,fa[i]);
	}
	m=read();
	for(int i=1;i<=m;++i)
	{
		int opt=read(),x=read();
		if(opt==0)
		{
			if(col[x])
			{
				int y=b.find(x);
				b.access(x);
				b.splay(y);
				printf("%d\n",b.mx[b.c[y][1]]); 
			}
			else
			{
				int y=w.find(x);
				w.access(x);
				w.splay(y);
				printf("%d\n",w.mx[w.c[y][1]]); 
			}
		}
		else if(opt==1)
		{
			if(col[x])
			{
				col[x]=0;
				b.cut(x);
				w.link(x,fa[x]);
			}
			else
			{
				col[x]=1;
				w.cut(x);
				b.link(x,fa[x]);
			}
		}
		else
		{
			int y=read();
			b.access(x);
			b.splay(x);
			b.val[x]=y;
			w.access(x);
			w.splay(x);
			w.val[x]=y;
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值