P5314 [Ynoi2011] ODT
我永远喜欢数据结构
题目传送门
给出
n 个点的树和q 次操作,点有点权,操作有两种类型:
不会全局平衡二叉树,但是两只
重链剖分,考虑用树状数组维护点权的差分数组,用平衡树求第
考虑对于每个点维护其所有轻儿子的点权的平衡树,查询时暴力插入 / 删除父亲、重儿子以及它本身。
那么对于一次路径修改,只有路径上重链顶端的父亲的平衡树会受到修改。
所以每次先树状数组路径加,然后删除这些平衡树上原来的点权,插入新的点权即可。
时间复杂度为 pbds::tree,代码特别好写。
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std; using namespace __gnu_pbds;
#define P pair<int, int>
#define fi first
#define se second
#define eb emplace_back
#define ins insert
namespace lzyqwq {
template<class T> void read(T &x) {
x = 0; T f = 1; char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - 48; x *= f;
}
template<class T> void write(T x) {
if (x > 9) write(x / 10); putchar(x % 10 + 48);
}
template<class T> void print(T x, char ed = '\n') {
if (x < 0) putchar('-'), x = -x; write(x), putchar(ed);
}
const int N = 1e6 + 1; vector<int> g[N];
int n, q, a[N], dep[N], top[N], dfn[N], sz[N], son[N], fa[N], cnt, id[N], ed[N];
tree<P, null_type, less<P>, rb_tree_tag,
tree_order_statistics_node_update> tr[N];
struct FenwickTree {
int sum[N]; int B(int x) { return x & -x; }
void M(int x, int v) { for (; x <= n; x += B(x)) sum[x] += v; }
int Q(int x) { int r = 0; for (; x; x -= B(x)) r += sum[x]; return r; }
void add(int l, int r, int d) { M(l, d); M(r + 1, -d); }
} fwt;
void dfs1(int u) {
sz[u] = 1;
for (int v : g[u])
if (v != fa[u]) {
dep[v] = dep[u] + 1; fa[v] = u; dfs1(v);
sz[u] += sz[v]; if (sz[v] > sz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int t) {
top[u] = t; dfn[u] = ++cnt; id[cnt] = u;
fwt.M(cnt, a[u] - a[id[cnt - 1]]); if (son[u]) dfs2(son[u], t);
for (int v : g[u])
if (v != fa[u] && v != son[u]) dfs2(v, v), tr[u].ins(P{a[v], v});
ed[u] = cnt;
}
int val(int x) { return fwt.Q(dfn[x]); }
void add(int u, int x, int y, bool op) {
if (op) tr[u].ins(P{x, y}); else tr[u].erase(P{x, y});
}
void mdf(int x, int y, bool op) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
add(fa[top[x]], val(top[x]), top[x], op); x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
if (fa[x] && x != son[fa[x]]) add(fa[x], val(x), x, op);
}
void cadd(int x, int y, int v) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
fwt.add(dfn[top[x]], dfn[x], v); x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x, y); fwt.add(dfn[x], dfn[y], v);
}
void Main() {
read(n); read(q); for (int i = 1; i <= n; ++i) read(a[i]);
for (int i = 1, u, v; i < n; ++i) read(u), read(v), g[u].eb(v), g[v].eb(u);
dfs1(1); dfs2(1, 1);
for (int op, x, y, v; q--;) {
read(op); read(x); read(y);
if (op & 1) read(v), mdf(x, y, 0), cadd(x, y, v), mdf(x, y, 1);
else {
add(x, val(x), x, 1); if (fa[x]) add(x, val(fa[x]), fa[x], 1);
if (son[x]) add(x, val(son[x]), son[x], 1);
print(tr[x].find_by_order(y - 1)->fi);
add(x, val(x), x, 0); if (fa[x]) add(x, val(fa[x]), fa[x], 0);
if (son[x]) add(x, val(son[x]), son[x], 0);
}
}
}
}
signed main() { return lzyqwq::Main(), 0; }