[BZOJ4551][TJOI2016&HEOI2016]树

BZOJ
Luogu
题意:给一棵以1为根的有根树,初始时只有1上面有标记。操作是给一个点打上标记,或者询问一个点最近的打了标记的祖先。

sol

据说多刷水题有益身心健康
显然一个点打了标记以后只可能影响到它子树的答案。所以打一个标记就是对子树做一个区间覆盖,线段树上每个点保留深度最大的打了标记的节点编号。可以标记永久化。

code

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 100005;
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
struct edge{int to,next;}a[N<<1];
int n,q,head[N],cnt,dep[N],dfn[N],low[N],t[N<<2];
void dfs(int u,int f)
{
	dfn[u]=++cnt;dep[u]=dep[f]+1;
	for (int e=head[u];e;e=a[e].next)
	{
		int v=a[e].to;if (v==f) continue;
		dfs(v,u);
	}
	low[u]=cnt;
}
void Modify(int x,int l,int r,int ql,int qr,int u)
{
	if (l>=ql&&r<=qr)
	{
		t[x]=dep[u]>dep[t[x]]?u:t[x];
		return;
	}
	int mid=l+r>>1;
	if (ql<=mid) Modify(x<<1,l,mid,ql,qr,u);
	if (qr>mid) Modify(x<<1|1,mid+1,r,ql,qr,u);
}
int Query(int x,int l,int r,int u)
{
	if (l==r) return t[x];
	int mid=l+r>>1,s;
	if (u<=mid) s=Query(x<<1,l,mid,u);
	else s=Query(x<<1|1,mid+1,r,u);
	return dep[s]>dep[t[x]]?s:t[x];
}
int main()
{
	n=gi();q=gi();
	for (int i=1;i<n;i++)
	{
		int u=gi(),v=gi();
		a[++cnt]=(edge){v,head[u]};head[u]=cnt;
		a[++cnt]=(edge){u,head[v]};head[v]=cnt;
	}
	cnt=0;dfs(1,0);
	Modify(1,1,n,1,n,1);
	while (q--)
	{
		char ch=getchar();
		while (ch!='C'&&ch!='Q') ch=getchar();
		int u=gi();
		if (ch=='C') Modify(1,1,n,dfn[u],low[u],u);
		else printf("%d\n",Query(1,1,n,dfn[u]));
	}
	return 0;
}
posted @ 2018-01-18 13:05  租酥雨  阅读(277)  评论(0编辑  收藏  举报