题意:
给出一棵树,有两种操作:
C x:标记点x;
Q x:查询某个点的最近被标记祖先;
n,m<=100000;
题解:
首先我们发现如果标记了一个点,其影响是对于个子树,也就是一段DFS区间的;
那么我们可以转化成一个序列上的问题:区间加入一个值,单点查询最大值;
然后直接标记永久化搞个线段树套set就可以了,时间复杂度O(nlog^2n);
【我怎么突然感觉不用套set直接维护最小值就行呢。。。
代码:
#include
#include
#include
#include
#define N 110000
#define pr pair
#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];
settr[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 &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