P4092 [HEOI2016/TJOI2016] 树
P4092 [HEOI2016/TJOI2016] 树
在 2016 年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树,根为
-
标记操作:对某个结点打上标记。(在最开始,只有结点
有标记,其他结点均无标记,而且对于某个结点,可以打多次标记。) -
询问操作:询问某个结点最近的一个打了标记的祖先。(这个结点本身也算自己的祖先)
你能帮帮她吗?
提示
Solution:
十分好写的题目,我们考虑点亮一个点会带来的影响,显然,点亮一个点只会对其子树产生影响,所以我们先求出这颗子树上的 dfs序 然后记录一下每个点的子树下的 dfs序范围
然后这题就做完了 。
Code:
#include<bits/stdc++.h> const int N=1e5+5; using namespace std; struct Segmnet_Tree{ struct Tree{ int val; }t[N<<2]; #define ls x<<1 #define rs x<<1|1 void pushup(int x) { t[x].val=max(t[ls].val,t[rs].val); } void upd(int x,int l,int r,int L,int R,int k) { if(L<=l&&r<=R) { t[x].val=max(t[x].val,k);return; } int mid=l+r>>1; if(L<=mid)upd(ls,l,mid,L,R,k); if(mid<R)upd(rs,mid+1,r,L,R,k); } void query(int x,int l,int r,int pos,int &res) { res=max(res,t[x].val); if(l==r)return; int mid=l+r>>1; if(pos<=mid)query(ls,l,mid,pos,res); else query(rs,mid+1,r,pos,res); } }T; vector<int> E[N]; int n,m,tot; int rid[N],st[N],ed[N]; void dfs(int x,int fa) { st[x]=++tot;rid[tot]=x; for(auto y : E[x])if(y!=fa) { dfs(y,x); } ed[x]=tot; } char c[10]; void work() { cin>>n>>m; for(int i=2,x,y;i<=n;i++) { scanf("%d%d",&x,&y); E[x].push_back(y);E[y].push_back(x); } dfs(1,0); T.upd(1,1,n,1,n,1); for(int i=1,x;i<=m;i++) { scanf("%s",c);scanf("%d",&x); if(c[0]=='C') { T.upd(1,1,n,st[x],ed[x],st[x]); } else { int res=0; T.query(1,1,n,st[x],res); printf("%d\n",rid[res]); } } } int main() { //freopen("tree.in","r",stdin);freopen("tree.out","w",stdout); work(); return 0; }