QOJ971 Binary Search Tree
QOJ971 Binary Search Tree
维护 \(n\) 棵二叉搜索树 \(T_1 \sim T_n\),支持 \(q\) 次操作:
- 给定 \(l,r,x\),对 \(i \in [l,r]\) 向 \(T_i\) 中插入 \(x\)。保证 \(x\) 两两不同。
- 给定 \(i,x\),在 \(T_i\) 上递归寻找 \(x\),查询访问的所有节点的权值和。
\(n,q \le 2\times 10^5\),2 秒,256 MB。
换维扫描线,维护时间轴。固定 \(i\),设 \(a_t=x\) 表示 \(t\) 时刻插入 \(T_i\) 的值,扫到 \(l\) 和 \(r+1\) 时进行切换。
查询给出时间前缀 \(1 \sim r\),依次将 \(a_1 \sim a_r\) 插入 \(T_i\)。

维护 \(b_x=t\) 表示 \(x\) 的插入时刻,若 \(x\) 始终未插入视作 \(+\infty\)。查询 \(1 \sim r\) 时 \(T_i=\{x \mid b_x\le r\}\)。
建立 \(b_x\) 的小根笛卡尔树。注意到 BST 本质是插入时间为优先级的 Treap,时间序列换维后,笛卡尔树和 \(T_i\) 等价。
查询 \(x\) 时访问的节点是 \(x \leadsto \text{root}\) 根链,取所有 \(b_x \le r\) 的节点权值和。笛卡尔树上 \(b\) 值递增,找到最深的 \(b_x \le r\) 的祖先 \(y\),取根链和即为答案。
将问题拍到 \(b\) 序列上,只要找出 \(y\le x\land b_y \le r\) 的最大的 \(y\),查询 \([1,y]\) 中后缀 \(\min\) 的带权和即可。对右侧同理求解。
单侧递归线段树维护区间 \(\min\),支持前后缀 \(\min\) 带权和即可。复杂度 \(O(q \log^2 n)\)。
const int N = 2e5 + 5, inf = 1e9;
int n, q, m, b[N]; i64 ans[N];
struct discrete {
vector<int> d;
void add(int x) {d.pb(x);}
void init() {
sort(all(d)), d.erase(unique(all(d)), d.end());
m = d.size();
}
int operator[] (int x) const {
return lower_bound(all(d), x) - d.begin() + 1;
}
int val(int x) {return d[x-1];}
} D;
vector<tuple<int, int, int>> P[N]; // (t, x, op)
vector<pair<int, int>> Q[N]; // (t, x)
struct segtree {
#define ls lc[rt]
#define rs rc[rt]
int tot = 1, val[4*N], lc[4*N], rc[4*N];
i64 pre[4*N], suf[4*N];
i64 calcl(int x, int rt) {
if (x <= val[rt]) return 0;
if (!ls) return suf[rt];
if (x <= val[rs]) return calcl(x, ls);
return calcl(x, rs) + suf[rt] - suf[rs];
}
i64 calcr(int x, int rt) {
if (x <= val[rt]) return 0;
if (!ls) return pre[rt];
if (x <= val[ls]) return calcr(x, rs);
return pre[rt] - pre[ls] + calcr(x, ls);
}
void pushup(int rt) {
val[rt] = min(val[ls], val[rs]);
pre[rt] = pre[ls] + calcr(val[ls], rs);
suf[rt] = calcl(val[rs], ls) + suf[rs];
}
void set(int rt, int c, int x) {
val[rt] = c, ls = rs = 0;
pre[rt] = suf[rt] = (x < 0 || c == inf) ? 0 : D.val(x);
}
void build(int l = 1, int r = m, int rt = 1) {
if (l == r) return set(rt, inf, l);
int mid = (l + r) >> 1; ls = ++tot, rs = ++tot;
build(l, mid, ls), build(mid+1, r, rs), pushup(rt);
}
void update(int x, int c, int l = 1, int r = m, int rt = 1) {
if (l == r) return set(rt, c, l);
int mid = (l + r) >> 1;
if (x <= mid) update(x, c, l, mid, ls);
else update(x, c, mid+1, r, rs);
pushup(rt);
}
int qmin(int tl, int tr, int l = 1, int r = m, int rt = 1) {
if (tl <= l && r <= tr) return val[rt];
int mid = (l + r) >> 1;
if (tl <= mid && mid < tr) return min(qmin(tl, tr, l, mid, ls), qmin(tl, tr, mid+1, r, rs));
return tl <= mid ? qmin(tl, tr, l, mid, ls) : qmin(tl, tr, mid+1, r, rs);
}
i64 qpre(int tl, int tr, int x) {
if (tl > tr) return 0;
vector<int> vec;
auto qry = [&](auto&& qry, int l, int r, int rt) -> void {
if (tl <= l && r <= tr) return vec.pb(rt), void();
int mid = (l + r) >> 1;
if (tl <= mid) qry(qry, l, mid, ls);
if (tr > mid) qry(qry, mid+1, r, rs);
};
qry(qry, 1, m, 1);
i64 res = 0;
for (int rt : vec) {
if (x <= val[rt]) continue;
res += calcr(x, rt), x = val[rt];
}
return res;
}
i64 qsuf(int tl, int tr, int x) {
if (tl > tr) return 0;
vector<int> vec;
auto qry = [&](auto&& qry, int l, int r, int rt) -> void {
if (tl <= l && r <= tr) return vec.pb(rt), void();
int mid = (l + r) >> 1;
if (tl <= mid) qry(qry, l, mid, ls);
if (tr > mid) qry(qry, mid+1, r, rs);
};
qry(qry, 1, m, 1); reverse(all(vec));
i64 res = 0;
for (int rt : vec) {
if (x <= val[rt]) continue;
res += calcl(x, rt), x = val[rt];
}
return res;
}
} T;
void _main() {
cin >> n >> q;
vector<int> vec;
for (int i = 1, op, l, r, x; i <= q; i++) {
cin >> op;
if (op == 1) {
cin >> l >> r >> x, D.add(x);
P[l].pb(i, x, +1), P[r+1].pb(i, x, -1);
} else {
cin >> r >> x, D.add(x);
Q[r].pb(i, x), vec.pb(i);
}
}
D.init(), T.build(), fill(b + 1, b + m + 1, inf);
for (int i = 1; i <= n; i++) {
auto ask = [](int x, int r) -> i64 {
i64 res = 0;
int lo = 1, hi = x, y = -1;
while (lo <= hi) {
int mid = (lo + hi) >> 1;
if (T.qmin(mid, x) <= r) y = mid, lo = mid+1;
else hi = mid-1;
}
res += T.qsuf(1, y, inf);
lo = x, hi = m, y = m+1;
while (lo <= hi) {
int mid = (lo + hi) >> 1;
if (T.qmin(x, mid) <= r) y = mid, hi = mid-1;
else lo = mid+1;
}
res += T.qpre(y, m, b[x] <= r ? b[x] : inf);
return res;
};
for (auto [t, x, op] : P[i]) {
b[D[x]] = (op == 1 ? t : inf);
T.update(D[x], b[D[x]]);
}
for (auto [t, x] : Q[i])
ans[t] = ask(D[x], t);
}
for (int i : vec) cout << ans[i] << '\n';
}

浙公网安备 33010602011771号