Brief Description

您需要写一种数据结构,支持:

  1. 更改一个点的点权
  2. 求一个子树的最小点权
  3. 换根

Algorithm Design

我们先忽略第三个要求。

看到要求子树的最小点权,我们想到使用dfs序。容易看到,一个节点的子树在dfs序中的范围就是\([l(x),r(x)]\),所以我们把树结构变成了线性结构,从而变成了一个RMQ问题,我们使用线段树即可求解。

对于换根,我们不必重新求出拓扑结构。我们考察换根会影响到的节点。对于新根的子树中的节点,一定没有影响,对于不是新根祖先的节点,一定也没有影响。所以我们只考虑新根的祖先。

我们可以看出,换成新根以后,祖先的覆盖范围就变成了全树抛去新根到祖先路径上距离祖先距离最近的节点的子树大小,设这个点为y,那么dfs序中的范围就是\([1,l[y]-1] \cup [r[y]+1, n]\)。

所以问题就变成了如何求树上离某个点距离最近的儿子。显然可以使用树上倍增来求。

Code

#include <algorithm>
#include <cstdio>
using std::max;
using std::min;
const int maxn = 100010;
int q[maxn], ind = 0, l[maxn], r[maxn], n, m, root, val[maxn], deep[maxn],
fa[maxn][20];
int cnt = 0;
struct edge {
int to, next;
} e[maxn];
int last[maxn];
struct seg {
int l, r, mn;
} t[maxn << 2];
void insert(int x, int y) {
e[++cnt].to = y;
e[cnt].next = last[x];
last[x] = cnt;
}
void update(int k) { t[k].mn = min(t[k << 1].mn, t[k << 1 | 1].mn); }
void dfs(int x) {
l[x] = ++ind;
q[ind] = x;
for (int i = 1; i <= 16; i++) {
if (deep[x] < (1 << i))
break;
fa[x][i] = fa[fa[x][i - 1]][i - 1];
}
for (int i = last[x]; i; i = e[i].next) {
fa[e[i].to][0] = x;
deep[e[i].to] = deep[x] + 1;
dfs(e[i].to);
}
r[x] = ind;
}
void build(int k, int l, int r) {
t[k].l = l, t[k].r = r;
int mid = (l + r) >> 1;
if (l == r) {
t[k].mn = val[q[l]];
return;
}
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
t[k].mn = min(t[k << 1].mn, t[k << 1 | 1].mn);
}
void modify(int k, int pos, int val) {
int l = t[k].l, r = t[k].r, mid = (l + r) >> 1;
if (l == r) {
t[k].mn = val;
return;
}
if (pos <= mid)
modify(k << 1, pos, val);
else
modify(k << 1 | 1, pos, val);
update(k);
}
int query(int k, int x, int y) {
int l = t[k].l, r = t[k].r, mid = (l + r) >> 1;
if (x <= l && r <= y)
return t[k].mn;
int ans = 0x3f3f3f;
if (x <= mid)
ans = min(ans, query(k << 1, x, y));
if (y > mid)
ans = min(ans, query(k << 1 | 1, x, y));
return ans;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input", "r", stdin);
#endif
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
int f;
scanf("%d %d", &f, &val[i]);
if (f)
insert(f, i);
}
dfs(root = 1);
#ifndef ONLINE_JUDGE
for (int i = 1; i <= ind; i++)
printf("%d ", q[i]);
printf("\n");
#endif
build(1, 1, n);
while (m--) {
char ch[5];
int x;
scanf("%s %d", ch, &x);
if (ch[0] == 'V') {
int val;
scanf("%d", &val);
modify(1, l[x], val);
} else if (ch[0] == 'E')
root = x;
else {
if (root == x)
printf("%d\n", t[1].mn);
else if (l[x] <= l[root] && r[x] >= r[root]) { // x is the father of root
int y = root, d = deep[y] - deep[x] - 1;
for (int i = 0; i <= 16; i++)
if (d & (1 << i))
y = fa[y][i];
printf("%d\n", min(query(1, 1, l[y] - 1), query(1, r[y] + 1, n)));
} else
printf("%d\n", query(1, l[x], r[x]));
}
}
return 0;
}

[bzoj3306]树——树上倍增+dfs序+线段树的更多相关文章

  1. 【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树

    题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\), ...

  2. 【bzoj3545/bzoj3551】[ONTAK2010]Peaks/加强版 Kruskal+树上倍增+Dfs序+主席树

    bzoj3545 题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询 ...

  3. BZOJ4034 [HAOI2015]树上操作+DFS序+线段树

    参考:https://www.cnblogs.com/liyinggang/p/5965981.html 题意:是一个数据结构题,树上的,用dfs序,变成线性的: 思路:对于每一个节点x,记录其DFS ...

  4. BZOJ_4034 [HAOI2015]树上操作 【树链剖分dfs序+线段树】

    一 题目 [HAOI2015]树上操作 二 分析 树链剖分的题,这里主要用到了$dfs$序,这题比较简单的就是不用求$lca$. 1.和树链剖分一样,先用邻接链表建双向图. 2.跑两遍$dfs$,其实 ...

  5. ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang(树上分块+dfs序+线段树)

    题意 链接:https://nanti.jisuanke.com/t/A1998 给出一个有根树(根是1),有n个结点.初始的时候每个结点的值都是0.下面有q个操作,操作有两种,操作1.将深度为L(根 ...

  6. Comet OJ - Contest #11 D isaster 重构树+倍增+dfs序+线段树

    发现对于任意一条边,起决定性作用的是节点编号更大的点. 于是,对于每一条边,按照节点编号较大值作为边权,按照最小生成树的方式插入即可. 最后用线段树维护 dfs 序做一个区间查询即可. Code: # ...

  7. BZOJ - 4196 软件包管理器 (树链剖分+dfs序+线段树)

    题目链接 设白色结点为未安装的软件,黑色结点为已安装的软件,则: 安装软件i:输出结点i到根的路径上的白色结点的数量,并把结点i到根的路径染成黑色.复杂度$O(nlog^2n)$ 卸载软件i:输出结点 ...

  8. 洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)

    P3178 [HAOI2015]树上操作 题目链接:https://www.luogu.org/problemnew/show/P3178 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边 ...

  9. 【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询

    题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作 ...

随机推荐

  1. 涉及到大小变化,类似QScrollArea判断大小是否显示滚动条

    涉及到大小变化,类似QScrollArea判断大小是否显示滚动条的情况要注意 这两个属性的设置:

  2. 机器学习 (二) 多变量线性回归 Linear Regression with Multiple Variables

    文章内容均来自斯坦福大学的Andrew Ng教授讲解的Machine Learning课程,本文是针对该课程的个人学习笔记,如有疏漏,请以原课程所讲述内容为准.感谢博主Rachel Zhang 的个人 ...

  3. Java IO 之 FileFilter与FilenameFilter

    FileFilter与FilenameFilter可以实现对文件的过滤,他们都是接口,具体的过滤规则需要我们自己编写 1.FileFilter package org.zln.io.file; imp ...

  4. Python数据分析(一)pandas数据切片

    1.获取行或列数据 loc——通过行标签索引行数据 iloc——通过行号索引行数据 ix——通过行标签或者行号索引行数据(基于loc和iloc 的混合) 同理,索引列数据也是如此! import pa ...

  5. flask-sqlalchemy 用法总结

    Flask-SQLAlchemy是一个Flask扩展,能够支持多种数据库后台,我们可以不需要关心SQL的处理细节,操作数据库,一个基本关系对应一个类,而一个实体对应类的实例对象.Flask是一个轻量级 ...

  6. Codeforces 662C(快速沃尔什变换 FWT)

    感觉快速沃尔什变换和快速傅里叶变换有很大的区别啊orz 不是很明白为什么位运算也可以叫做卷积(或许不应该叫卷积吧) 我是看 http://blog.csdn.net/liangzhaoyang1/ar ...

  7. BZOJ4602: [Sdoi2016]齿轮 DFS 逆元

    这道题就是一个DFS,有一篇奶牛题几乎一样.但是这道题卡精度. 这道题网上的另一篇题解是有问题的.取对数这种方法可以被轻松卡.比如1e18 与 (1e9-1)*(1e9+1)取对数根本无法保证不被卡精 ...

  8. [51nod1503]猪和回文 DP

    ---题面--- 题解: 首先观察到题目要求的是合法回文串的个数,而回文串要求从前往后和从后往前是一样的,因此我们假设有两只猪,分别从左上和右下开始走,走相同的步数最后相遇,那么它们走的路能拼在一起构 ...

  9. BZOJ3223: Tyvj 1729 文艺平衡树 无旋Treap

    一开始光知道pushdown却忘了pushup......... #include<cstdio> #include<iostream> #include<cstring ...

  10. 活泼的CSS 3动态气泡按钮制作

    这一次,我们正在创造一个有用的设置与对CSS3的多重背景和动画的力量动画按钮.通过此按钮包,您可以很容易地变成一个动画按钮,在您的网页上的任何链接只是指定一个类名.没有必要JavaScript.四色主 ...