题目描述

在2016年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树(根为1),有以下两种操作:

  1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个结点,可以打多次标记。)

  2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖先)

你能帮帮他吗?

输入输出格式

输入格式:

输入第一行两个正整数N和Q分别表示节点个数和操作次数

接下来N-1行,每行两个正整数u,v(1≤u,v≤n)表示u到v有一条有向边

接下来Q行,形如“opernum”oper为“C”时表示这是一个标记操作,oper为“Q”时表示这是一个询问操作对于每次询问操作。

输出格式:

输出一个正整数,表示结果

输入输出样例

输入样例#1: 复制

5 5
1 2
1 3
2 4
2 5
Q 2
C 2
Q 2
Q 5
Q 3
输出样例#1: 复制

1
2
2
1

说明

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+; int n,m;
int opt,x;
int head[N],num_edge;
struct Edge
{
int v,nxt;
}edge[N<<];
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<<]; typedef TREE* Tree;
Tree Root,now_node=tree; inline int read()
{
char c=getchar();
for(;!isdigit(c);c=getchar())
if(c=='C') return ;
else if(c=='Q') return ;
int num=;
for(;isdigit(c);c=getchar())
num=num*+c-'';
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=;
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+;
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>>;
root->num=;
if(l==r)
return;
build(root->lson,l,root->mid);
build(root->rson,root->mid+,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=;
}
} 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+,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=,u,v;i<n;++i)
{
u=read(),v=read();
add_edge(u,v);
add_edge(v,u);
}
dfs1();
dfs2();
build(Root,,n);
for(int i=;i<=m;++i)
{
opt=read(),x=read();
if(opt==)
update(Root,node[x].s,node[x].t,x);
else
printf("%d\n",query(Root,node[x].s));
}
return ;
}

P4092 [HEOI2016/TJOI2016]树的更多相关文章

  1. 洛谷 P4092 [HEOI2016/TJOI2016]树 || bzoj4551

    https://www.lydsy.com/JudgeOnline/problem.php?id=4551 https://www.luogu.org/problemnew/show/P4092 这当 ...

  2. 洛谷P4092 [HEOI2016/TJOI2016]树 并查集/树链剖分+线段树

    正解:并查集/树链剖分+线段树 解题报告: 传送门 感觉并查集的那个方法挺妙的,,,刚好又要复习下树剖了,所以就写个题解好了QwQ 首先说下并查集的方法趴QwQ 首先离线,读入所有操作,然后dfs遍历 ...

  3. [洛谷P4092][HEOI2016/TJOI2016]树

    题目大意:给你一棵树,有两个操作: $C\;x:$给第$x$个节点打上标记 $Q\;x:$询问第$x$个节点的祖先中最近的打过标记的点(自己也是自己的祖先) 题解:树剖,可以维护区间或,然后若一段区间 ...

  4. [HEOI2016/TJOI2016]树

    [HEOI2016/TJOI2016]树 思路 做的时候也是糊里糊涂的 就是求最大值的线段树 错误 线段树写错了 #include <bits/stdc++.h> #define FOR( ...

  5. luogu题解 P4092 【[HEOI2016/TJOI2016]树】树链剖分

    题目链接: https://www.luogu.org/problemnew/show/P4092 瞎扯--\(O(Q \log^3 N)\)解法 这道先yy出了一个\(O(Q \log^3 N)\) ...

  6. 题解 P4092 【[HEOI2016/TJOI2016]树】

    参考了皎月半洒花的博客 看到树想到树剖,由于要取距自己到根离自己最近的标记点,刚开始想到线段树里存节点深度,查询时返回最大值.但是这样的话只能得到节点深度,无法得知节点编号,就想倍增乱搞一下,求出标记 ...

  7. 暴力 【p4092】[HEOI2016/TJOI2016]树

    Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下两种操作: 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其 ...

  8. [题解向] Luogu4092 [HEOI2016/TJOI2016]树

    #\(\mathcal{\color{red}{Description}}\) \(Link\) 给定一棵以\(1\)为根的树,有两种操作: \(C: \ \ x\)给点\(x\)打上花标记. \(Q ...

  9. [HEOI2016/TJOI2016]排序 线段树+二分

    [HEOI2016/TJOI2016]排序 内存限制:256 MiB 时间限制:6000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 在2016年,佳媛姐姐喜欢上了数字序列.因而 ...

随机推荐

  1. 微软商店一直安装不上Intel Media SDK DFP

    具体表现为一直安装失败,但是下载进度条一直在,无法去除. 此方法来自 https://answers.microsoft.com/en-us/windows/forum/all/error-code- ...

  2. Linux 服务器修改时间与时间同步

    设置时间 date --set '2015-11-23 0:10:40' # 方法一,通用 timedatectl set-time '2015-11-23 08:10:40' # 容器内可能不支持 ...

  3. 百人研发团队的难题:研发管理、绩效考核、组织文化和OKR

    分享一个公司规模近200,研发占一半的创业公司 Worktile 在研发团队管理方面的玩法,仅供百人左右研发团队参考~ 什么是研发团队?简单的说,你熟悉的那帮穿格子衬衫,以程序员为核心组成的团队,就是 ...

  4. Linux磁盘管理系列 — LVM和RAID

    一.逻辑卷管理器(LVM) 1.什么是逻辑卷管理器(LVM) LVM是逻辑盘卷管理(Logical Volume Manager)的简称,它是Linux环境下对卷进行操作的抽象层. LVM是建立在硬盘 ...

  5. hdu 6661 Acesrc and String Theory (后缀数组)

    大意: 求重复$k$次的子串个数 枚举重复长度$i$, 把整个串分为$n/i$块, 如果每块可以$O(1)$计算, 那么最终复杂度就为$O(nlogn)$ 有个结论是: 以$j$开头的子串重复次数最大 ...

  6. Dockerfile编写,以及设置一个自启动脚本

    FROM:指定基础镜像,必须为第一个命令 MAINTAINER: 维护者信息 RUN:构建镜像时执行的命令 ADD:将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问 ...

  7. PEB TEB结构体使用

    PEB TEB结构体使用一个可执行文件被OS加载到内存,并处理完成相关的模块加载,导入表处理……及其他必须处理后,形成一个进程.在OS内核中保存有一份关于这个进程的身份证信息,就是平常看到的HANDL ...

  8. Dev GridControl 子集合标题

    显示效果: 设置: this.gridView3.OptionsView.ShowViewCaption = true; this.gridView3.ViewCaption = "资产明细 ...

  9. 一、openfeign的自动配置

    所有文章 https://www.cnblogs.com/lay2017/p/11908715.html 正文 openfeign是一种声明式的webservice客户端调用框架.你只需要声明接口和一 ...

  10. https、加密安全

    1.Https HTTPS在传输的过程中会涉及到三个密钥: 服务器端的公钥和私钥,用来进行非对称加密 客户端生成的随机密钥,用来进行对称加密 一个HTTPS请求实际上包含了两次HTTP传输,可以细分为 ...