题目描述
在2016年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树(根为1),有以下两种操作:
-
标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个结点,可以打多次标记。)
- 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖先)
你能帮帮他吗?
输入输出格式
输入格式:
输入第一行两个正整数N和Q分别表示节点个数和操作次数
接下来N-1行,每行两个正整数u,v(1≤u,v≤n)表示u到v有一条有向边
接下来Q行,形如“opernum”oper为“C”时表示这是一个标记操作,oper为“Q”时表示这是一个询问操作对于每次询问操作。
输出格式:
输出一个正整数,表示结果
输入输出样例
说明
30%的数据,1 ≤ N, Q ≤ 1000
70%的数据,1 ≤ N, Q ≤ 10000
100%的数据,1 ≤ N, Q ≤ 100000
// luogu-judger-enable-o2 //其实不是树剖,而是dfs序+线段树 //每个点的dfs序是一段区间,这段区间就是它的孩子们 //当我们更改一个点的时候,就把它的孩子们全改了 (要判断一下改不改) //如果它的儿子们的num(要求的祖先)的dep小于lazy的deep,就修改它的儿子们的lazy和num,改成当前点的lazy //否则就不改 这样就避免了后来的标记覆盖了之前的标记 而且我们的标记一定是当前最优的 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+5; int n,m; int opt,x; int head[N],num_edge; struct Edge { int v,nxt; }edge[N<<1]; struct Node { int fa,son; int s,t; int size; int dep,top; }node[N]; struct TREE { TREE *lson,*rson; int l,r,mid; int num,lazy; }tree[N<<2]; typedef TREE* Tree; Tree Root,now_node=tree; inline int read() { char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='C') return 1; else if(c=='Q') return 2; int num=0; for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num; } inline void add_edge(int u,int v) { edge[++num_edge].v=v; edge[num_edge].nxt=head[u]; head[u]=num_edge; } void dfs1(int u) { node[u].size=1; for(int i=head[u],v;i;i=edge[i].nxt) { v=edge[i].v; if(v==node[u].fa) continue; node[v].fa=u; node[v].dep=node[u].dep+1; dfs1(v); node[u].size+=node[v].size; if(node[v].size>node[node[u].son].size) node[u].son=v; } } int bound; void dfs2(int u) { node[u].s=++bound; if(node[u].son) { dfs2(node[u].son); for(int i=head[u],v;i;i=edge[i].nxt) { v=edge[i].v; if(v==node[u].fa||v==node[u].son) continue; dfs2(v); } } node[u].t=bound; } void build(Tree &root,int l,int r) { root=++now_node; root->l=l,root->r=r,root->mid=l+r>>1; root->num=1; if(l==r) return; build(root->lson,l,root->mid); build(root->rson,root->mid+1,r); } inline void pushdown(Tree root) { if(root->lazy) { if(node[root->lazy].dep>node[root->lson->lazy].dep) root->lson->lazy=root->lazy; if(node[root->lazy].dep>node[root->rson->lazy].dep) root->rson->lazy=root->lazy; if(node[root->lazy].dep>node[root->lson->num].dep) root->lson->num=root->lazy; if(node[root->lazy].dep>node[root->rson->num].dep) root->rson->num=root->lazy; root->lazy=0; } } void update(Tree root,int l,int r,int val) { if(l==root->l&&r==root->r) { root->num=node[root->num].dep>node[val].dep?root->num:val; //这儿也要比较一下的,一开始没比较,直接改的 root->lazy=node[root->lazy].dep>node[val].dep?root->lazy:val; //因为这个区间不一定只改一次,所以也要比较 当时抽了 return; } pushdown(root); if(r<=root->mid) update(root->lson,l,r,val); else if(l>root->mid) update(root->rson,l,r,val); else { update(root->lson,l,root->mid,val); update(root->rson,root->mid+1,r,val); } } int query(Tree root,int pos) { if(root->l==root->r) return root->num; pushdown(root); if(pos<=root->mid) return query(root->lson,pos); else return query(root->rson,pos); } int main() { n=read(),m=read(); for(int i=1,u,v;i<n;++i) { u=read(),v=read(); add_edge(u,v); add_edge(v,u); } dfs1(1); dfs2(1); build(Root,1,n); for(int i=1;i<=m;++i) { opt=read(),x=read(); if(opt==1) update(Root,node[x].s,node[x].t,x); else printf("%d ",query(Root,node[x].s)); } return 0; }