1. 程式人生 > >【省內訓練2018-10-28】排序二叉樹

【省內訓練2018-10-28】排序二叉樹

【思路要點】

  • 若將一個序列按照元素大小排序,那麼其對應的排序二叉樹即為插入時間對應的笛卡爾樹,並且,被刪除的元素可以視作插入時間為正無窮的元素。
  • 一個點在排序二叉樹上所有的祖先即其左側/右側對應的所有插入時間為後/字首最小值的點。
  • 離線操作,對權值離散化,並用線段樹維護。
  • 對於一個修改 i i ,在其對應區間的左端點將對應元素的插入時間改為 i
    i
    ,在出右端點後將對應元素的插入時間改為正無窮。
  • 對於一個詢問,我們需要計算的是從某處向左/右,插入時間作為後/字首最大值出現的位置的權值和,可用李超線段樹維護。
  • 時間複雜度 O ( M L
    o g 2 M + N ) O(MLog^2M+N)

【程式碼】

#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;
}