[HEOI2016/TJOI2016]树

就上树剖。
维护区间最右端的点。
主要是顺手复习一下树剖。
30min手速很不错。

#include<iostream>
#include<cstdio>
#define ll long long
#define N 100005

ll n;

ll head[N];
struct P{
	int to,next;
}e[N << 1];

ll cnt;

inline void add(int x,int y){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}

ll q;

ll siz[N],dfn[N],idfn[N],dep[N],son[N],top[N],fa[N];

inline void dfs1(int x,int f){
	siz[x] = 1;
	dep[x] = dep[f] + 1;
	fa[x] = f;
	for(int i = head[x];i;i = e[i].next){
		int v = e[i].to;
		if(v == f)continue;
		dfs1(v,x);
		if(siz[v] > siz[son[x]])
		son[x] = v;
		siz[x] += siz[v];
	}
}

ll dfncnt;

inline void dfs2(int u,int t){
	dfn[u] = ++dfncnt;
	idfn[dfncnt] = u;
	top[u] = t;
	if(son[u])dfs2(son[u],t);
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].to;
		if(v == fa[u] || v == son[u])continue;
		dfs2(v,v);
	}
} 

struct Tree{int right;}T[N << 4];

#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
#define root 1,1,n
#define r(x) T[x].right
#define mid ((l + r) >> 1)

inline void up(int x){
	if(r(rs(x)))
	r(x) = r(rs(x));
	else
	r(x) = r(ls(x));
}

inline void Add(int x,int l,int r,int to){
	if(l == r){
		r(x) = idfn[l];
		return;
	}
	if(to <= mid)
	Add(ls(x),l,mid,to);
	else
	Add(rs(x),mid + 1,r,to);
	up(x);
}

inline ll find(int x,int l,int r,int tl,int tr){
	if(tl <= l && r <= tr){
		return r(x);
	}
	ll p = 0;
	if(tr > mid)
	p = find(rs(x),mid + 1,r,tl,tr);
	if(!p && tl <= mid)
	p = find(ls(x),l,mid,tl,tr);
	return p; 
}

int main(){
	scanf("%lld%lld",&n,&q);
	for(int i = 1;i < n;++i){
		ll x,y;
		scanf("%lld%lld",&x,&y);
		add(x,y);
		add(y,x);
	}
	dfs1(1,0);
	dfs2(1,1);
	Add(root,1);
	while(q -- ){
		char a = getchar();
		while(a != 'C' && a != 'Q')
		a = getchar();
		if(a == 'C'){
			ll x;
			scanf("%lld",&x);
			Add(root,dfn[x]);
		}
		if(a == 'Q'){
			ll ans = 0;
			ll x;
			scanf("%lld",&x);
			while(x){
				ans = find(root,dfn[top[x]],dfn[x]);
				if(ans)
				break;
				x = fa[top[x]];
			}
			std::cout<<ans<<std::endl;
		}
		a = '.';
	}
}
原文地址:https://www.cnblogs.com/dixiao/p/15206312.html