#\(\mathcal{\color{red}{Description}}\)

\(Link\)

给定一棵以\(1\)为根的树,有两种操作:

\(C: \ \ x\)给点\(x\)打上花标记。

\(Q: \ \ x\)求点\(x\)的最近被标记祖先(自身包括)

#\(\mathcal{\color{red}{Solution}}\)

这个题……操作水的很但是我还是没能秒掉,我们考虑对于一个节点,单纯考虑线段树的话好像并不可做。那么我们先来考虑简单的,对于一个点,如果要查找一个点的最近标记祖先,那我们不断查找他和他的\(top\)之间的节点即可,即不断进行跳链操作。那么我们线段树维护什么信息呢?首先要满足结合律,其次\(query\)的结果可以直接拿来用。所以我们考虑维护一段链条上面的深度最深的被标记节点。

int qmark(int u, int v){
int ans = -1 ;
while(top[u] != top[v]){
if (dep[top[u]] < dep[top[v]]) swap(u, v) ;
ans = query(1, 1, N, id[top[u]], id[u]) ;
if (ans != -1) return qnq[ans] ;
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v) ;
return qnq[ query(1, 1, N, id[u], id[v]) ];
}

查询的时候直接查询当前节点和根节点之间即可。

#include<cstdio>
#include<cstring>
#include<iostream>
#define il inline
#define MAXN 400001
#define ls(x) x << 1
#define rs(x) x << 1 | 1
#define to(k) e[k].t using namespace std ;
char pt ;
int id[MAXN], s[MAXN + 1050], qnq[MAXN];
int i, a, b, tot, N, M, cnt;
int head[MAXN], fa[MAXN], hs[MAXN], top[MAXN], dep[MAXN], sub[MAXN] ;
struct node{
int t, next ;
}e[MAXN]; il void add(int u, int v){
e[++ cnt].t = v ;
e[cnt].next = head[u] ;
head[u] = cnt ;
}
il int qr(){
int k = 0;
char c = getchar() ;
while(!isdigit(c)) c = getchar() ;
while(isdigit(c)){
k = (k << 1) + (k << 3) + c - 48 ;
c = getchar() ;
}
return k ;
} il void p_u(int rt){
s[rt] = max(s[ls(rt)], s[rs(rt)]) ;
}
il void update(int rt, int l, int r, int ul, int ur){
if (ul <= l && ur >= r){
s[rt] = l ;
return ;
}
int mid = (l + r) >> 1 ;
if (ul <= mid) update(ls(rt), l, mid, ul, ur) ;
if (ur > mid) update(rs(rt), mid + 1, r, ul, ur) ;
p_u(rt) ;
}
il int query(int rt, int l, int r, int nl, int nr){
int res = -1 ;
if (nl <= l && nr >= r) {res = s[rt];return res ;}
int mid = (l + r) >> 1 ;
if (nl <= mid)res = max(res, query(ls(rt), l, mid, nl, nr)) ;
if (nr > mid)res = max(res, query(rs(rt), mid + 1, r, nl, nr)) ;
return res ;
} void dfs1(int now, int f, int deep){
fa[now] = f ;
dep[now] = deep ;
int hson = -1 ;
sub[now] = 1 ;
for(int k = head[now]; k ; k = e[k].next){
if(to(k) == f) continue ;
dfs1(to(k), now, deep + 1) ;
sub[now] += sub[to(k)] ;
if(hson < sub[to(k)]) hs[now] = to(k), hson = sub[to(k)] ;
}
}
void dfs2(int now, int tp){
id[now] = ++ tot;
top[now] = tp ;
qnq[tot] = now ;
if(!hs[now]) return ;
dfs2(hs[now], tp) ;
for(int k = head[now]; k ; k = e[k].next){
if(to(k) == fa[now] || to(k) == hs[now]) continue ;
dfs2(to(k), to(k)) ;
}
}
int qmark(int u, int v){
int ans = -1 ;
while(top[u] != top[v]){
if (dep[top[u]] < dep[top[v]]) swap(u, v) ;
ans = query(1, 1, N, id[top[u]], id[u]) ;
if (ans != -1) return qnq[ans] ;
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v) ;
return qnq[ query(1, 1, N, id[u], id[v]) ];
} int main(){
cin >> N >> M ;
memset(s, -1, sizeof(s)) ;
for(i = 1; i < N; i ++){
a = qr(), b = qr() ;
add(a, b) ;
add(b, a) ;
}
dfs1(1, 0, 1) ;
dfs2(1, 1) ;
update(1, 1, N, 1, 1) ;
for(i = 1; i <= M; i ++){
cin >> pt ;
if (pt == 'Q'){
b = qr() ;
printf("%d\n", qmark(b, 1)) ;
}
else {
a = qr() ;
update(1, 1, N, id[a], id[a]) ;
}
}
}

[题解向] Luogu4092 [HEOI2016/TJOI2016]树的更多相关文章

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

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

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

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

  3. [HEOI2016/TJOI2016]树

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

  4. 【题解】P4091 [HEOI2016/TJOI2016]求和

    [题解]P4091 [HEOI2016/TJOI2016]求和 [P4091 HEOI2016/TJOI2016]求和 可以知道\(i,j\)从\(0\)开始是可以的,因为这个时候等于\(0\).这种 ...

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

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

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

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

  7. 题解 P4093 【[HEOI2016/TJOI2016]序列】

    这道题原来很水的? noteskey 一开始以为是顺序的 m 个修改,然后选出一段最长子序列使得每次修改后都满足不降 这 TM 根本不可做啊! 于是就去看题解了,然后看到转移要满足的条件的我发出了黑人 ...

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

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

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

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

随机推荐

  1. Rider中Winform开发支持预览(5)

    1.Rider .netCore3.0 winform设计器支持预览,这点vs目前还不支持. 2.不过winform下控件选择工具栏都是没有图标的

  2. sql server删除重复记录只保留一条

    今天遇到一个历史导入数据重复的问题,于是要删除重复的记录,一开始想用子查询的方式找到要删除记录的id删除,后来发现DELETE语句可以直接用外连接,这样更加简单,效率也更高. delete sys_p ...

  3. Prometheus 告警收敛

    Prometheus 告警收敛 告警面临最大问题,是警报太多,相当于狼来了的形式.收件人很容易麻木,不再继续理会.关键的告警常常被淹没.在一问题中,alertmanger在一定程度上得到很好解决. P ...

  4. python学习--大数据与科学计算第三方库简介

    大数据与科学计算  库名称 简介 pycuda/opencl GPU高性能并发计算 Pandas python实现的类似R语言的数据统计.分析平台.基于NumPy和Matplotlib开发的,主要用于 ...

  5. net core 记录自定义端口多个方式

    1.直接修改 . 2.代码定义 public class Program { public static void Main(string[] args) { CreateWebHostBuilder ...

  6. 我遇到的WPF的坑

    转自 林德熙Blog 本文:我遇到的WPF的坑 目录 单例应用在多实例用户无法使用 标记方法被使用 当鼠标滑过一个被禁用的元素时,让ToolTip 显示 获取设备屏幕数量 获取当前域用户 绑定资源文件 ...

  7. 我是如何一步步编码完成万仓网ERP系统的(十三)库存 2.加权平均价

    https://www.cnblogs.com/smh188/p/11533668.html(我是如何一步步编码完成万仓网ERP系统的(一)系统架构) https://www.cnblogs.com/ ...

  8. 调试 Go 的代码生成

    原文:https://studygolang.com/articles/19815 这是一个创建于 2019-04-17 23:12:26 的文章,其中的信息可能已经有所发展或是发生改变. 2016 ...

  9. linux 搭建swoole

    1安装依赖包yum -y install gcc gcc-c++ autoconf automake yum -y install zlib zlib-devel openssl openssl-de ...

  10. js计算数组中元素出现的次数,并实现去重

    function getCount(arr, rank,ranktype){ var obj = {}, k, arr1 = []; for (var i = 0, len = arr.length; ...