Educational Codeforces Round 33 (Rated for Div. 2) F. Subtree Minimum Query(主席树合并)
题意
给定一棵 \(n\) 个点的带点权树,以 \(1\) 为根, \(m\) 次询问,每次询问给出两个值 \(p, k\) ,求以下值:
\(p\) 的子树中距离 \(p \le k\) 的所有点权最小值,询问强制在线。
\(n \le 10^5 , m \le 10^6, TL = 6s\)
题解
如果不强制在线,直接线段树合并就做完了。
强制在线,不难想到用一些可持久化的结构来维护这些东西。
其实可以类似线段树合并那样考虑,也就是说每次合并的时候我们依然使用儿子的信息。
只要在合并 \(x, y\) 共有部分的时候建出新节点,然后权值是 \(x, y\) 权值的较小值,其他的部分直接连向那些单独有的子树信息即可。
其实实现是这样的:
int Merge(int x, int y) {
if (!x || !y) return x | y;
int o = Newnode();
ls[o] = Merge(ls[x], ls[y]);
rs[o] = Merge(rs[x], rs[y]);
minv[o] = min(minv[x], minv[y]);
return o;
}
这样的话,既可以保留子树信息,又可以得到这个节点新的信息。
最后空间复杂度就是 \(O(n \log n)\) ,时间复杂度是 \(O((n + m) \log n)\) 的。
总结
强制在线问题,用可持久化数据结构去解决就行了,也就是把平常的数据结构记历史版本,并尽量用之前的信息。
代码
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define pb push_back
using namespace std;
template<typename T> inline bool chkmin(T &a, T b) {return b < a ? a = b, 1 : 0;}
template<typename T> inline bool chkmax(T &a, T b) {return b > a ? a = b, 1 : 0;}
inline int read() {
int x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
}
void File() {
#ifdef zjp_shadow
freopen ("F.in", "r", stdin);
freopen ("F.out", "w", stdout);
#endif
}
const int N = 1e5 + 1e3, inf = 0x3f3f3f3f;
#define lson ls[o], l, mid
#define rson rs[o], mid + 1, r
template<int Maxn>
struct Chair_Man_Tree {
int ls[Maxn], rs[Maxn], minv[Maxn], Size;
Chair_Man_Tree() { minv[0] = inf; }
inline int Newnode() {
int o = ++ Size; minv[o] = inf; return o;
}
void Update(int &o, int l, int r, int up, int uv) {
if (!o) o = Newnode();
if (l == r) { chkmin(minv[o], uv); return ; }
int mid = (l + r) >> 1;
up <= mid ? Update(lson, up, uv) : Update(rson, up, uv);
minv[o] = min(minv[ls[o]], minv[rs[o]]);
}
int Query(int o, int l, int r, int ql, int qr) {
if (!o) return inf;
if (ql <= l && r <= qr) return minv[o];
int mid = (l + r) >> 1;
if (qr <= mid) return Query(lson, ql, qr);
if (ql > mid) return Query(rson, ql, qr);
return min(Query(lson, ql, qr), Query(rson, ql, qr));
}
int Merge(int x, int y) {
if (!x || !y) return x | y;
int o = Newnode();
ls[o] = Merge(ls[x], ls[y]);
rs[o] = Merge(rs[x], rs[y]);
minv[o] = min(minv[x], minv[y]);
return o;
}
};
vector<int> G[N]; int val[N], rt[N], dep[N];
int n, S;
Chair_Man_Tree<N * 80> T;
void Dfs(int u, int fa = 0) {
dep[u] = dep[fa] + 1;
for (int v : G[u]) if (v != fa)
Dfs(v, u), rt[u] = T.Merge(rt[u], rt[v]);
T.Update(rt[u], 1, n, dep[u], val[u]);
}
int main () {
File();
n = read(); S = read();
For (i, 1, n)
val[i] = read();
For (i, 1, n - 1) {
int u = read(), v = read();
G[u].pb(v); G[v].pb(u);
}
Dfs(S);
int q = read(), ans = 0;
For (i, 1, q) {
int x = (read() + ans) % n + 1, k = (read() + ans) % n;
printf ("%d\n", ans = T.Query(rt[x], 1, n, dep[x], min(dep[x] + k, n)));
}
return 0;
}
Educational Codeforces Round 33 (Rated for Div. 2) F. Subtree Minimum Query(主席树合并)的更多相关文章
- Codeforces Educational Codeforces Round 44 (Rated for Div. 2) F. Isomorphic Strings
Codeforces Educational Codeforces Round 44 (Rated for Div. 2) F. Isomorphic Strings 题目连接: http://cod ...
- Educational Codeforces Round 71 (Rated for Div. 2)-F. Remainder Problem-技巧分块
Educational Codeforces Round 71 (Rated for Div. 2)-F. Remainder Problem-技巧分块 [Problem Description] ...
- [Educational Codeforces Round 81 (Rated for Div. 2)]E. Permutation Separation(线段树,思维,前缀和)
[Educational Codeforces Round 81 (Rated for Div. 2)]E. Permutation Separation(线段树,思维,前缀和) E. Permuta ...
- Educational Codeforces Round 33 (Rated for Div. 2) E. Counting Arrays
题目链接 题意:给你两个数x,yx,yx,y,让你构造一些长为yyy的数列,让这个数列的累乘为xxx,输出方案数. 思路:考虑对xxx进行质因数分解,设某个质因子PiP_iPi的的幂为kkk,则这个 ...
- Educational Codeforces Round 33 (Rated for Div. 2) 题解
A.每个状态只有一种后续转移,判断每次转移是否都合法即可. #include <iostream> #include <cstdio> using namespace std; ...
- Educational Codeforces Round 33 (Rated for Div. 2)A-F
总的来说这套题还是很不错的,让我对主席树有了更深的了解 A:水题,模拟即可 #include<bits/stdc++.h> #define fi first #define se seco ...
- Educational Codeforces Round 33 (Rated for Div. 2) D. Credit Card
D. Credit Card time limit per test 2 seconds memory limit per test 256 megabytes input standard inpu ...
- Educational Codeforces Round 33 (Rated for Div. 2) C. Rumor【并查集+贪心/维护集合最小值】
C. Rumor time limit per test 2 seconds memory limit per test 256 megabytes input standard input outp ...
- Educational Codeforces Round 33 (Rated for Div. 2) B. Beautiful Divisors【进制思维/打表】
B. Beautiful Divisors time limit per test 2 seconds memory limit per test 256 megabytes input standa ...
随机推荐
- Linux常用软件启动、停止、重启命令
一.PHP 启动命令: /usr/local/php5/sbin/php-fpm 停止命令: pkill php-fpm 二.MySQL 启动命令: /etc/init.d/mysqld start ...
- Python_面向对象基础
概念 类 一类抽象的事物,是描述了一类事物有哪些属性或者行为,但不是具体——模子. 实例 一个依托于类的规范存在的,被赋予了具体属性值的实际存在的物体. 对象 就是实例,实例的另外一个名称,相当于别名 ...
- Golang开发工具LiteIDE使用方法整理
安装 参考github的说明 添加GOPATH 创建workspace 创建新文件 运行程序 Liteide中运行程序有两种方式: FR(FileRun)是编译并运行单个文件,可以使用Shift + ...
- Linux系统mysql使用(二)
一.查看某数据库的表 # 假设此时数据库名为hiveuse hive; show tables;
- WIN10 devtoolsuser
visual studio - UWP: What is the DevToolsUser Password? - Stack Overflowhttps://stackoverflow.com/qu ...
- API的设计与安全
前后端分离是个浪潮,原来只有APP客户端会考虑这些,现在连Web都要考虑前后端分离 . 这里面不得不谈的就是API的设计和安全性,这些个问题不解决好,将会给服务器安全和性能带来很大威胁 . API的设 ...
- [官网]Linux版本历史
This is a list of links to every changelog. https://kernelnewbies.org/LinuxVersions 总结一下 2.6.x 存在了八年 ...
- Struts2——通配符,Action Method_DMI
Action wildcard 通配符(配置量降到最低) 使用通配符,就是为了配置简便,但是一定遵守“约定优于配置”原则,约定就是做项目之前最好事先与项目组的人或是自己规定好命名规则. 多个* {1 ...
- Object.defineProperties()与Proxy对象代理
Object.defineProperties() 了不起啊..vue.js通过它实现双向绑定的 Object.defineProperties(obj,props) 方法直接在一个对象上定义新的属性 ...
- jenkins 邮箱设置
一.先设置管理员邮箱地址 二.设置邮箱