【模板】主席树
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;
}