博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Educational Codeforces Round 33 (Rated for Div. 2) F. Subtree Minimum Query(主席树合并)
阅读量:5175 次
发布时间:2019-06-13

本文共 3422 字,大约阅读时间需要 11 分钟。

题意

给定一棵 \(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 
#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_backusing namespace std;template
inline bool chkmin(T &a, T b) {return b < a ? a = b, 1 : 0;}template
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, rtemplate
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
G[N]; int val[N], rt[N], dep[N];int n, S;Chair_Man_Tree
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;}

转载于:https://www.cnblogs.com/zjp-shadow/p/9774279.html

你可能感兴趣的文章
JSP/Servlet基础
查看>>
dig 命令
查看>>
linux编程
查看>>
SpringMVC11文件上传
查看>>
mysql数据库名,表名大小写问题
查看>>
js---定时器
查看>>
接口测试全流程
查看>>
如何不传入对象就获得某对象的方法---ThreadLocal类
查看>>
手机页面分页加载更多
查看>>
Shell的for和select
查看>>
[知识管理] - 自己做的一个程序员求职知识管理的小网站
查看>>
git代码统计
查看>>
【转】ext/iconv/.libs/iconv.o: In function `_php_iconv_strlen'
查看>>
学习docker on windows (1): 为什么要使用docker
查看>>
杭电acm step 动态规划专题总结(1)简单的动态规划问题
查看>>
Windows 下 Apache HTTP Server 安装、配置以及与 Tomcat 的整合(附图)
查看>>
OpenGL 简介
查看>>
安卓模拟器导入通讯录
查看>>
内部类
查看>>
(转)Unity3D命令行Build
查看>>