题意:
给出一棵树,有两种操作:
C x:标记点x;
Q x:查询某个点的最近被标记祖先;
n,m<=100000;
题解:
首先我们发现如果标记了一个点,其影响是对于个子树,也就是一段DFS区间的;
那么我们可以转化成一个序列上的问题:区间加入一个值,单点查询最大值;
然后直接标记永久化搞个线段树套set就可以了,时间复杂度O(nlog^2n);
【我怎么突然感觉不用套set直接维护最小值就行呢。。。
代码:
#include<set>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110000
#define pr pair<int,int>
#define lson l,mid,no<<1
#define rson mid+1,r,no<<1|1
using namespace std;
typedef long long ll;
char op[N];
int next[N<<1],to[N<<1],head[N],ce;
int L[N],R[N],deep[N],tim;
bool cov[N];
set<pr>tr[N<<2];
void add(int x,int y)
{
to[++ce]=y;
next[ce]=head[x];
head[x]=ce;
}
void dfs(int x,int pre)
{
L[x]=++tim;
deep[x]=deep[pre]+1;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=pre)
{
dfs(to[i],x);
}
}
R[x]=tim;
}
pr getmax(const set<pr> &s)
{
if(!s.size()) return pr(0,0);
return *(--s.end());
}
void update(int l,int r,int no,int st,int en,pr val)
{
if(st<=l&&r<=en)
{
tr[no].insert(val);
}
else
{
int mid=l+r>>1;
if(en<=mid) update(lson,st,en,val);
else if(st>mid) update(rson,st,en,val);
else update(lson,st,en,val),update(rson,st,en,val);
}
}
pr query(int l,int r,int no,int k)
{
if(l==r)
return getmax(tr[no]);
else
{
int mid=l+r>>1;
if(k<=mid) return max(query(lson,k),getmax(tr[no]));
else return max(query(rson,k),getmax(tr[no]));
}
}
int main()
{
int n,m,i,j,k,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs(1,0);
cov[1]=1;
tr[1].insert(pr(1,1));
for(i=1;i<=m;i++)
{
scanf("%s%d",op,&x);
if(op[0]=='C')
{
if(!cov[x])
{
update(1,n,1,L[x],R[x],pr(deep[x],x));
cov[x]=1;
}
}
else
{
printf("%d\n",query(1,n,1,L[x]).second);
}
}
return 0;
}