[bzoj3306]树——树上倍增+dfs序+线段树
Brief Description
您需要写一种数据结构,支持:
- 更改一个点的点权
- 求一个子树的最小点权
- 换根
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序+线段树的更多相关文章
- 【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树
题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\), ...
- 【bzoj3545/bzoj3551】[ONTAK2010]Peaks/加强版 Kruskal+树上倍增+Dfs序+主席树
bzoj3545 题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询 ...
- BZOJ4034 [HAOI2015]树上操作+DFS序+线段树
参考:https://www.cnblogs.com/liyinggang/p/5965981.html 题意:是一个数据结构题,树上的,用dfs序,变成线性的: 思路:对于每一个节点x,记录其DFS ...
- BZOJ_4034 [HAOI2015]树上操作 【树链剖分dfs序+线段树】
一 题目 [HAOI2015]树上操作 二 分析 树链剖分的题,这里主要用到了$dfs$序,这题比较简单的就是不用求$lca$. 1.和树链剖分一样,先用邻接链表建双向图. 2.跑两遍$dfs$,其实 ...
- ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang(树上分块+dfs序+线段树)
题意 链接:https://nanti.jisuanke.com/t/A1998 给出一个有根树(根是1),有n个结点.初始的时候每个结点的值都是0.下面有q个操作,操作有两种,操作1.将深度为L(根 ...
- Comet OJ - Contest #11 D isaster 重构树+倍增+dfs序+线段树
发现对于任意一条边,起决定性作用的是节点编号更大的点. 于是,对于每一条边,按照节点编号较大值作为边权,按照最小生成树的方式插入即可. 最后用线段树维护 dfs 序做一个区间查询即可. Code: # ...
- BZOJ - 4196 软件包管理器 (树链剖分+dfs序+线段树)
题目链接 设白色结点为未安装的软件,黑色结点为已安装的软件,则: 安装软件i:输出结点i到根的路径上的白色结点的数量,并把结点i到根的路径染成黑色.复杂度$O(nlog^2n)$ 卸载软件i:输出结点 ...
- 洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)
P3178 [HAOI2015]树上操作 题目链接:https://www.luogu.org/problemnew/show/P3178 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边 ...
- 【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询
题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作 ...
随机推荐
- python 字典(dict)按键和值排序
python 字典(dict)的特点就是无序的,按照键(key)来提取相应值(value),如果我们需要字典按值排序的话,那可以用下面的方法来进行: 1 下面的是按照value的值从大到小的顺序来排序 ...
- Qt Demo Http 解析网址 Openssl
今天练习了一下Qt 解析http协议,在Demo中使用到了Openssl 一上午的时间都是编译openssl,不过还是没有成功,很遗憾,这里整理了有关这个Demo的本件 网盘连接:见下方评论吧,长传太 ...
- python学习总结---网络编程
网络编程 相关概念 - OSI七层模型:它从低到高分别是:物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. - TCP/IP: 在OSI七层模型基础上简化抽象出来的一套网络协议簇,现在得到 ...
- 在阿里云上遇见更好的Oracle(二)
从上一篇文章的反馈来看,大家还是喜欢八卦多过技术细节,那这一篇继续一些题外话,说说我对“去IOE”的看法. 对同一件事情,参与的没参与的人,讨论起来,都会有各自的立场.所以这里先申明一下,以下内容只是 ...
- [CH5302]金字塔
题面 虽然探索金字塔是极其老套的剧情,但是有一队探险家还是到了某金字塔脚下.经过多年的研究,科学家对这座金字塔的内部结构已经有所了解.首先,金字塔由若干房间组成,房间之间连有通道.如果把房间看作节点, ...
- z 变换
1. z 变换 单位脉冲响应为 \(h[n]\) 的离散时间线性时不变系统对复指数输入 \(z^n\) 的响应 \(y[n]\) 为 \[ \tag{1} y[n] = H(z) z^{n}\] 式中 ...
- linux备忘录-账号管理与ACL权限设定
知识 账号管理中的一些文件结构 /etc/passwd 每一行的内容都为下面结构 账号名称:密码:UID:GID:用户信息说明:家目录:shell ---- UID ---- -- 0 -> 代 ...
- django之上传文件和图片
文件上传:文件上传功能是网站开发中必定会使用到的技术,在django项目中也是如此,下面会详细讲述django中上传文件的前端和后端的具体处理步骤: 前端HTML代码实现: 1.在前端中,我们需要填入 ...
- winform label去背景
以pictureBox上面显示一个不需要背景的label为例: 1.保证label的父控件是该pictureBox: 2.label的color属性为transParent:
- capacilitys 持续集成
目前看好像是说以docker为例来看看这个权限到底是怎么来的? 可以通过在二进制上setcap得到,也可以通过函数自己用setcap得到,两种方法,docker肯定是第二种方法啊,docker中间肯定 ...