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
",Query(1,1,n,dfn[u]));
}
return 0;
}