【模板】主席树

Update at 2019.10.9

  • 主席树的核心思想是多棵权值线段树对区间的划分具有一致性,且相同区间的值具有可减性。
  • 可持久化的思想体现在对任意区间 \([l,r]\) 的处理上。

代码如下

#include <bits/stdc++.h>

using namespace std;

const int maxn = 2e5 + 10;

struct node {
	int sz;
	node *ls, *rs;
	void pull() { // be careful
		this->sz = 0;
		if (ls) {
			this->sz += ls->sz;
		} 
		if (rs) {
			this->sz += rs->sz;
		}
	}
} pool[maxn * 20];
inline node *newnode() {
	static int tot = 0;
	return &pool[tot++];
}

node *insert(node *pre, int l, int r, int pos, int val) {
	node *cur = newnode();
	if (pre) { // be careful
		*cur = *pre;
	}
	if (l == r) {
		cur->sz += val;
		return cur;
	}
	int mid = l + r >> 1;
	if (pos <= mid) {
		cur->ls = insert(pre ? pre->ls : NULL, l, mid, pos, val);
	} else {
		cur->rs = insert(pre ? pre->rs : NULL, mid + 1, r, pos, val);
	}
	cur->pull();
	return cur;
}
int kth(node *cur, node *pre, int l, int r, int k) {
	if (l == r) {
		return l;
	}
	int mid = l + r >> 1;
	int lsz = 0;
	if (cur && cur->ls) lsz += cur->ls->sz; // be careful
	if (pre && pre->ls) lsz -= pre->ls->sz;
	if (k <= lsz) {
		return kth(cur ? cur->ls : NULL, pre ? pre->ls : NULL, l, mid, k);
	} else {
		return kth(cur ? cur->rs : NULL, pre ? pre->rs : NULL, mid + 1, r, k - lsz);
	}
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int n, m;
	cin >> n >> m;
	vector<int> a(n + 1), d;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		d.push_back(a[i]);
	}
	sort(d.begin(), d.end());
	d.erase(unique(d.begin(), d.end()), d.end());
	for (int i = 1; i <= n; i++) {
		a[i] = lower_bound(d.begin(), d.end(), a[i]) - d.begin() + 1;
	}
	int range = d.size();
	vector<node*> rt(n + 1);
	for (int i = 1; i <= n; i++) {
		rt[i] = insert(rt[i - 1], 1, range, a[i], 1);
	}
	while (m--) {
		int l, r, k;
		cin >> l >> r >> k;
		cout << d[kth(rt[r], rt[l - 1], 1, range, k) - 1] << endl;
	}
	return 0;
}
posted @ 2018-12-14 22:34  shellpicker  阅读(132)  评论(0编辑  收藏  举报