P4092 [HEOI2016/TJOI2016]树
题目描述
在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+; 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]树的更多相关文章
- 洛谷 P4092 [HEOI2016/TJOI2016]树 || bzoj4551
https://www.lydsy.com/JudgeOnline/problem.php?id=4551 https://www.luogu.org/problemnew/show/P4092 这当 ...
- 洛谷P4092 [HEOI2016/TJOI2016]树 并查集/树链剖分+线段树
正解:并查集/树链剖分+线段树 解题报告: 传送门 感觉并查集的那个方法挺妙的,,,刚好又要复习下树剖了,所以就写个题解好了QwQ 首先说下并查集的方法趴QwQ 首先离线,读入所有操作,然后dfs遍历 ...
- [洛谷P4092][HEOI2016/TJOI2016]树
题目大意:给你一棵树,有两个操作: $C\;x:$给第$x$个节点打上标记 $Q\;x:$询问第$x$个节点的祖先中最近的打过标记的点(自己也是自己的祖先) 题解:树剖,可以维护区间或,然后若一段区间 ...
- [HEOI2016/TJOI2016]树
[HEOI2016/TJOI2016]树 思路 做的时候也是糊里糊涂的 就是求最大值的线段树 错误 线段树写错了 #include <bits/stdc++.h> #define FOR( ...
- luogu题解 P4092 【[HEOI2016/TJOI2016]树】树链剖分
题目链接: https://www.luogu.org/problemnew/show/P4092 瞎扯--\(O(Q \log^3 N)\)解法 这道先yy出了一个\(O(Q \log^3 N)\) ...
- 题解 P4092 【[HEOI2016/TJOI2016]树】
参考了皎月半洒花的博客 看到树想到树剖,由于要取距自己到根离自己最近的标记点,刚开始想到线段树里存节点深度,查询时返回最大值.但是这样的话只能得到节点深度,无法得知节点编号,就想倍增乱搞一下,求出标记 ...
- 暴力 【p4092】[HEOI2016/TJOI2016]树
Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下两种操作: 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其 ...
- [题解向] Luogu4092 [HEOI2016/TJOI2016]树
#\(\mathcal{\color{red}{Description}}\) \(Link\) 给定一棵以\(1\)为根的树,有两种操作: \(C: \ \ x\)给点\(x\)打上花标记. \(Q ...
- [HEOI2016/TJOI2016]排序 线段树+二分
[HEOI2016/TJOI2016]排序 内存限制:256 MiB 时间限制:6000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 在2016年,佳媛姐姐喜欢上了数字序列.因而 ...
随机推荐
- Echarts设置y轴值间隔 以及设置 barWidth : 30,//柱图宽度
需求:如图,y轴之间的距离太小,这样就太过于拥挤了,现在要修改echarts里面的属性,设置y轴值间隔让图表看上去舒服一些. 其实很多问题,真的只是因为自己没有好好的看文档,很多文档上面都写的 ...
- idea的项目结构
idea项目结构: 一般是创建一个empty project,然后再创建一个个的Module.
- python pip命令安装相当于yum仓库
进入pip目录: 创建pip.conf: 打开pip.conf [global] index-url=https://mirrors.aliyun.com/pypi/simple/ trusted-h ...
- hdu 2822 ~!!!!!!坑死我
首先 在此哀悼... 为我逝去的时间哀悼... 每一步都确定再去写下一步吧...日狗 不过还是有点收获的.. 对优先队列的使用 有了进一步的理解 先上代码 #include<iostrea ...
- 手把手教小白安装Erlang
Erlang(['ə:læŋ])是一种通用的面向并发的编程语言,它有瑞典电信设备制造商爱立信所辖的CS-Lab开发,目的是创造一种可以应对大规模并发活动的编程语言和运行环境. Erlang官网:htt ...
- Psychedelic therapy
Psychedelic therapy Psychedelic therapy早期在美国应该取得了相当大的成功,方法是在给予受试者充分的心理准备后,一次性运用极高剂量的LSD(0.3−0.6毫克),试 ...
- JS 页面刷新以及页面返回的几种方式
1.通过标签形式的跳转页面 <a class="popup" href="~/WeiXin/Shoppingguide/StockData">&l ...
- 回忆一下Node(随时更改,想到什么写什么)
什么是Node? Node.js 是一个基于Chrome V8 引擎的JavaScript运行环境 Node.js使用了一个事件驱动.非阻塞式I/O的模型,使其轻量又高效 事件驱动: 任务执行,发布者 ...
- Python排序算法(六)——归并排序(MERGE-SORT)
有趣的事,Python永远不会缺席! 如需转发,请注明出处:小婷儿的python https://www.cnblogs.com/xxtalhr/p/10800699.html 一.归并排序(MERG ...
- jdk代理与cglib代理
1. jdk静态代理 jdk静态代理主要使用硬编码实现.他通过对在代理类中持有委托类的引用,来打到在委托类方法执行前和执行后进行处理,实现简单,容易理解. 代码如下: 1.业务逻辑接口 package ...