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年,佳媛姐姐喜欢上了数字序列.因而 ...
随机推荐
- 使用Jenkins的Git Parameter插件来从远程仓库拉取指定目录的内容
更换插件安装源 系统管理---插件管理---高级---升级站点,把默认的插件下载地址换成下面这个: https://mirrors.tuna.tsinghua.edu.cn/jenkins/updat ...
- ef core数据迁移的一点小感悟
ef core在针对mysql数据迁移的时候,有些时候没法迁移...有两种情况没法迁移,一种是因为efcore的bug问题导致没法迁移,这个在github上有个问题集,另外一种是对数据表进行较大幅度的 ...
- ESlint 格式化代码 备忘
vscode 代码格式化配置 vscode 菜单 文件->首选项->设置 --->进入扩展查找到ESlint,点击任一选项中的[在setting.json中配置],复制以下代码 { ...
- vue中将时间戳转换为YYYY-MM-dd hh:mm格式时间的组件
首先我们可以使用vue中的过滤方法将数据变成另一个格式 // html <span class="rate-time">{{rating.rateTime | form ...
- java读取文件的几种方式性能比较
//普通输入流读取文件内容 public static long checksumInputStream(Path filename) { try(InputStream in= Files.newI ...
- sql server动态分页
USE RYPlatformManagerDB GO SET ANSI_NULLS, QUOTED_IDENTIFIER ON GO CREATE Proc [dbo].[WEB_PageView] ...
- MySQL常见问题集锦及注意事项
一.表设计上的坑 1.字段设计 1.1 字段类型设计 尽量使用整型表示字符串: `INET_ATON(str)`,address to number `INET_NTOA(number)`,numbe ...
- 【Mybatis】缓存
一.概述 1.1 缓存的意义 1.2 mybatis持久层缓存 二.一级缓存 2.1 原理 2.2 一级缓存配置 一级缓存测试 三.二级缓存 3.1 原理 3.2 mybatis二级缓存配置 3.3 ...
- Java 函数调用是传值还是传引用? 从字节码角度来看看!
原文地址:点击打开
- 服务发现之consul理论整理_结合Docker+nginx+Tomcat简单部署案例
目录 一.理论概述 服务发现的概念简述 consul简述 二.部署docker+consul+Nginx案例 环境 部署 三.测试 四.总结 一.理论概述 服务发现的概念简述 在以前使用的是,N台机器 ...