bzoj-4551 [Tjoi2016&Heoi2016]树

题意:

给出一棵树,有两种操作:

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




你可能感兴趣的:(bzoj,数据结构)