【省內訓練2018-10-28】排序二叉樹
阿新 • • 發佈:2018-11-19
【思路要點】
- 若將一個序列按照元素大小排序,那麼其對應的排序二叉樹即為插入時間對應的笛卡爾樹,並且,被刪除的元素可以視作插入時間為正無窮的元素。
- 一個點在排序二叉樹上所有的祖先即其左側/右側對應的所有插入時間為後/字首最小值的點。
- 離線操作,對權值離散化,並用線段樹維護。
- 對於一個修改 ,在其對應區間的左端點將對應元素的插入時間改為 ,在出右端點後將對應元素的插入時間改為正無窮。
- 對於一個詢問,我們需要計算的是從某處向左/右,插入時間作為後/字首最大值出現的位置的權值和,可用李超線段樹維護。
- 時間複雜度 。
【程式碼】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; const int INF = 2e9; 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(""); } int n, m, tot, pos[MAXN]; struct SegmentTree { struct Node { int lc, rc, Min, index; ll pre, suf; } a[MAXN * 2]; int root, size, n, val[MAXN]; void build(int &root, int l, int r) { root = ++size; a[root].Min = INF; a[root].pre = a[root].suf = 0; if (l == r) {a[root].index = pos[l]; val[l] = INF; 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); } ll calpre(int pos, int d) { if (a[pos].lc == 0) { if (d > a[pos].Min) return a[pos].index; else return 0; } if (d > a[a[pos].rc].Min) return a[pos].pre + calpre(a[pos].rc, d); else return calpre(a[pos].lc, d); } ll calsuf(int pos, int d) { if (a[pos].lc == 0) { if (d > a[pos].Min) return a[pos].index; else return 0; } if (d > a[a[pos].lc].Min) return a[pos].suf + calsuf(a[pos].lc, d); else return calsuf(a[pos].rc, d); } void update(int root) { a[root].Min = min(a[a[root].lc].Min, a[a[root].rc].Min); a[root].pre = calpre(a[root].lc, a[a[root].rc].Min); a[root].suf = calsuf(a[root].rc, a[a[root].lc].Min); } void modify(int root, int l, int r, int pos, int d) { if (l == r) { a[root].Min = d; val[l] = 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, int d) { modify(root, 1, n, pos, d); } int tmp; ll querypre(int root, int l, int r, int pos) { if (pos >= r) { ll ans = calpre(root, tmp); chkmin(tmp, a[root].Min); return ans; } int mid = (l + r) / 2; ll ans = 0; if (mid < pos) ans += querypre(a[root].rc, mid + 1, r, pos); ans += querypre(a[root].lc, l, mid, pos); return ans; } ll querysuf(int root, int l, int r, int pos) { if (pos <= l) { ll ans = calsuf(root, tmp); chkmin(tmp, a[root].Min); return ans; } int mid = (l + r) / 2; ll ans = 0; if (mid >= pos) ans += querysuf(a[root].lc, l, mid, pos); ans += querysuf(a[root].rc, mid + 1, r, pos); return ans; } ll query(int p, int d) { ll ans = 0; tmp = d, ans += querypre(root, 1, n, p); tmp = d, ans += querysuf(root, 1, n, p); if (d > val[p]) ans -= pos[p]; return ans; } } ST; vector <pair <int, int> > op[MAXN]; set <int> st; map <int, int> mp; int opt[MAXN], l[MAXN], r[MAXN], x[MAXN]; ll ans[MAXN]; int main() { read(n), read(m); for (int i = 1; i <= m; i++) { read(opt[i]), read(l[i]); if (opt[i] == 1) read(r[i]), read(x[i]); else read(x[i]); st.insert(x[i]); } for (auto x : st) { pos[++tot] = x; mp[x] = tot; } ST.init(tot); for (int i = 1; i <= m; i++) { x[i] = mp[x[i]]; if (opt[i] == 1) op[l[i]].emplace_back(x[i], i), op[r[i] + 1].emplace_back(x[i], INF); } for (int i = 1; i <= m; i++) if (opt[i] == 2) op[l[i]].emplace_back(-x[i], i); for (int i = 1; i <= n; i++) for (auto x : op[i]) if (x.first > 0) ST.modify(x.first, x.second); else ans[x.second] = ST.query(-x.first, x.second); for (int i = 1; i <= m; i++) if (opt[i] == 2) writeln(ans[i]); return 0; }