【题目链接】
【思路要点】
- 若将一个序列按照元素大小排序,那么其对应的 T r e a p Treap Treap 即为权值对应的笛卡尔树,并且,被删除的元素可以视作权值为 0 0 0 的元素。
- 一个点在 T r e a p Treap Treap 上所有的祖先即其左侧/右侧对应的所有权值为后/前缀最大值的点。
- 离线操作,对权值离散化,并用线段树维护。
- 插入删除操作可以通过线段树的单调修改实现。
- 对于一个询问 ( x , y ) (x,y) (x,y) ,我们考虑计算 d e p t h x + d e p t h y − 2 ∗ d e p t h l c a ( x , y ) depth_x+depth_y-2*depth_{lca(x,y)} depthx+depthy−2∗depthlca(x,y) 。
- 其中 l c a ( x , y ) lca(x,y) lca(x,y) 即为区间 [ x , y ] [x,y] [x,y] 权值最大值的位置。 d e p t h x depth_x depthx 需要计算的是从 x x x 向左/右,权值作为后/前缀最大值出现的位置的个数,可用李超线段树维护。
- 时间复杂度 O ( N L o g 2 N ) O(NLog^2N) O(NLog2N) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct SegmentTree { struct Node { int lc, rc, pre, suf; unsigned Max; } a[MAXN * 2]; int root, size, n; void build(int &root, int l, int r) { root = ++size; a[root].Max = 0; a[root].pre = 0; a[root].suf = 0; if (l == r) return; int mid = (l + r) / 2; build(a[root].lc, l, mid); build(a[root].rc, mid + 1, r); } void init(int x) { n = x; root = size = 0; build(root, 1, n); } int calpre(int pos, unsigned d) { if (a[pos].lc == 0) { if (d < a[pos].Max) return 1; else return 0; } if (d < a[a[pos].rc].Max) return a[pos].pre + calpre(a[pos].rc, d); else return calpre(a[pos].lc, d); } int calsuf(int pos, unsigned d) { if (a[pos].lc == 0) { if (d < a[pos].Max) return 1; else return 0; } if (d < a[a[pos].lc].Max) return a[pos].suf + calsuf(a[pos].lc, d); else return calsuf(a[pos].rc, d); } void update(int root) { a[root].Max = max(a[a[root].lc].Max, a[a[root].rc].Max); a[root].pre = calpre(a[root].lc, a[a[root].rc].Max); a[root].suf = calsuf(a[root].rc, a[a[root].lc].Max); } void modify(int root, int l, int r, int pos, unsigned d) { if (l == r) { a[root].Max = d; return; } int mid = (l + r) / 2; if (mid >= pos) modify(a[root].lc, l, mid, pos, d); else modify(a[root].rc, mid + 1, r, pos, d); update(root); } void modify(int pos, unsigned d) { modify(root, 1, n, pos, d); } unsigned tmp; int querypre(int root, int l, int r, int pos) { if (pos >= r) { int ans = calpre(root, tmp); chkmax(tmp, a[root].Max); return ans; } int mid = (l + r) / 2, ans = 0; if (mid < pos) ans += querypre(a[root].rc, mid + 1, r, pos); ans += querypre(a[root].lc, l, mid, pos); return ans; } int querysuf(int root, int l, int r, int pos) { if (pos <= l) { int ans = calsuf(root, tmp); chkmax(tmp, a[root].Max); return ans; } int mid = (l + r) / 2, ans = 0; if (mid >= pos) ans += querysuf(a[root].lc, l, mid, pos); ans += querysuf(a[root].rc, mid + 1, r, pos); return ans; } int query(int x) { int ans = -1; tmp = 0; ans += querypre(root, 1, n, x); tmp = 0; ans += querysuf(root, 1, n, x); return ans; } int home; void lca(int root, int l, int r, int ql, int qr) { int mid = (l + r) / 2; if (l == ql && r == qr) { if (tmp > a[root].Max) return; chkmax(tmp, a[root].Max); if (l == r) { home = l; return; } lca(a[root].lc, l, mid, l, mid); lca(a[root].rc, mid + 1, r, mid + 1, r); return; } if (mid >= ql) lca(a[root].lc, l, mid, ql, min(qr, mid)); if (mid + 1 <= qr) lca(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); } int lca(int x, int y) { tmp = 0; if (x > y) swap(x, y); lca(root, 1, n, x, y); return home; } int query(int x, int y) { return query(x) + query(y) - 2 * query(lca(x, y)); } } ST; set <unsigned> st; map <unsigned, int> mp; int n, tot; unsigned opt[MAXN], x[MAXN], y[MAXN]; int main() { read(n); for (int i = 1; i <= n; i++) { read(opt[i]), read(x[i]); if (opt[i] != 1) read(y[i]); if (opt[i] == 0) st.insert(x[i]); } for (auto x : st) mp[x] = ++tot; ST.init(tot); for (int i = 1; i <= n; i++) { if (opt[i] == 0) { x[i] = mp[x[i]]; ST.modify(x[i], y[i]); } else if (opt[i] == 1) { x[i] = mp[x[i]]; ST.modify(x[i], 0); } else { x[i] = mp[x[i]]; y[i] = mp[y[i]]; writeln(ST.query(x[i], y[i])); } } return 0; }