[SPOJ2939]Qtree5

[SPOJ2939]Qtree5

Tags:题解


题意

链接
给你\(n\)个节点的黑白树,初始全黑。每次可以翻转某点颜色,或查询距离某点最近的白点的距离。\(n\le 10^5\)。强制LCT,不准动点分。

题解

这题神了。
LCT中每个splay的中序遍历是一条直上直下的链。

维护什么呢?

\(splay\)中的\(x\)点维护\(x\)\(splay\)子树中,在原树上深度最深和深度最浅的点、到达\(x\)\(splay\)子树中的点在原图上的子树中、最近的白点的距离。分别记为\(lm、rm\)

怎么维护呢?

需要维护原图信息那么开一个\(set\)维护虚子树
深度最浅的点是x的最左儿子,它的最近白点距离可能由以下几方面

  • 左子树的答案
  • 左子树的\(siz\)(若\(x\)为白点)
  • 左子树的\(siz+1+\)右子树的答案

同理维护最深的点。

怎么查呢?

\(x\)\(Access\)这样它就是这条链上最深的点了。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<set>
#define lc t[x].ch[0]
#define rc t[x].ch[1]
using namespace std;
const int N=2e5+10,inf=1e9;
int n,q,head[N],cnt;
struct edge{int next,to;}a[N];
struct Node{int ch[2],siz,lm,rm,col,fa;multiset<int> s;}t[N];
multiset<int>::iterator it;
void link(int x,int y) {a[++cnt]=(edge){head[x],y};head[x]=cnt;}
int isroot(int x) {return t[t[x].fa].ch[0]!=x&&t[t[x].fa].ch[1]!=x;}
int fin(int x) {return t[x].s.empty()?inf:*t[x].s.begin();}
void pushup(int x)
{
	t[x].siz=t[lc].siz+t[rc].siz+1;
	t[x].lm=min(t[lc].lm,t[lc].siz+min(t[x].col?0:inf,min(fin(x),t[rc].lm+1)));
	t[x].rm=min(t[rc].rm,t[rc].siz+min(t[x].col?0:inf,min(fin(x),t[lc].rm+1)));
}
void rotate(int x)
{
	int y=t[x].fa,z=t[y].fa;
	int k=t[y].ch[1]==x;
	if(!isroot(y)) t[z].ch[t[z].ch[1]==y]=x; t[x].fa=z;
	t[y].ch[k]=t[x].ch[k^1];                 t[t[x].ch[k^1]].fa=y;
	t[x].ch[k^1]=y;                          t[y].fa=x;
	pushup(y);
}
void splay(int x)
{
	while(!isroot(x))
	{
		int y=t[x].fa,z=t[y].fa;
		if(!isroot(y)) (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
		rotate(x);
	}
	pushup(x);
}
void Access(int x)
{
	for(int y=0;x;y=x,x=t[x].fa)
	{
		splay(x);t[x].s.insert(t[rc].lm+1);
		rc=y;it=t[x].s.lower_bound(t[rc].lm+1);
		if(it!=t[x].s.end()&&*it==t[rc].lm+1) t[x].s.erase(it);
		pushup(x);
	}
}
void dfs(int x,int fr)
{
	for(int i=head[x];i;i=a[i].next)
	{
		int R=a[i].to;if(fr==R) continue;
		t[R].fa=x;t[x].s.insert(inf+1);dfs(R,x);
	}
	pushup(x);
}
int main()
{
	cin>>n;
	t[0].lm=t[0].rm=inf+1;
	for(int i=1,x,y;i<n;i++)
		scanf("%d%d",&x,&y),link(x,y),link(y,x);
	cin>>q;dfs(1,0);
	for(int i=1;i<=q;i++)
	{
		int op,x;scanf("%d%d",&op,&x);
		if(op==0)
		{
			Access(x);splay(x);
			t[x].col^=1;pushup(x);
		}
		else
		{
			Access(x);splay(x);
			printf("%d\n",t[x].rm>n?-1:t[x].rm);
		}
	}
	return 0;
}
posted @ 2019-02-02 09:40  饕餮传奇  阅读(388)  评论(0编辑  收藏  举报