可持久化线段树不是一颗完全二叉树,所以不能用层次序编号,而应该直接记录每个节点的左、右子节点的编号。可持久化线段树维护了每次操作后线段树的历史形态。
下面举个简单的例子来理解一下:
以poj-2104为例;这棵树是一颗不用修改的线段树
题意:即多次查询,查询区间第K大的数。
POJ-2104 (区间第k大)
//主席树的学习--区间第k大
//区间第k大又可以用整体分治算法,归并树,线段树套平衡树,主席树来做
//以主席树为例来做
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 5;
struct SegmentTree{
int lc, rc;
int dat;//用来记录区间内元素的个数
}tree[maxn * 30];
int tot, root[maxn];//主席树的总点数和每个根
int a[maxn], b[maxn];//a用来存原数列,b用来存离散之后的
int n, m;
int cnt;
int build_tree(int l, int r) {
int step = tot++;
/*
tree[step].dat = 0;
if (l != r) {
int mid = (l + r) >> 1;
tree[step].lc = build_tree(l, mid);
tree[step].rc = build_tree(mid + 1, r);
}
*/
if (l == r) {
tree[step].dat = 0;
return step;
}
int mid = (l + r) >> 1;
tree[step].lc = build_tree(l, mid);
tree[step].rc = build_tree(mid + 1, r);
tree[step].dat = tree[tree[step].lc].dat + tree[tree[step].rc].dat;
return step;
}
int update(int rt, int pos, int val) {
int step = tot++;
int temp = step;
tree[step].dat = tree[rt].dat + val;
int l = 1, r = cnt;
while (l < r) {
int mid = (l + r) >> 1;
if (pos <= mid) {
tree[step].lc = tot++;
tree[step].rc = tree[rt].rc;
step = tree[step].lc;
rt = tree[rt].lc;
r = mid;
}
else{
tree[step].lc = tree[rt].lc;
tree[step].rc = tot++;
step = tree[step].rc;
rt = tree[rt].rc;
l = mid + 1;
}
tree[step].dat = tree[rt].dat + val;
}
return temp;
}
int query(int r1, int r2, int k) {
int l = 1, r = cnt;
while (l < r) {
int mid = (l + r) >> 1;
int tmp = tree[tree[r2].lc].dat - tree[tree[r1].lc].dat;
if (tmp >= k) {
r1 = tree[r1].lc;
r2 = tree[r2].lc;
r = mid;
}
else {
k -= tmp;
r1 = tree[r1].rc;
r2 = tree[r2].rc;
l = mid + 1;
}
}
return l;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
b[i - 1] = a[i];
}
sort(b, b + n);
cnt = unique(b, b + n) - b;
tot = 0;
root[0] = build_tree(1, cnt);
for (int i = 1; i <= n; i++) {
int tmp = (int)(lower_bound(b, b + cnt, a[i]) - b) + 1;
root[i] = update(root[i - 1], tmp, 1);
}
int l, r, k;
while (m--) {
cin >> l >> r >> k;
int tmp = query(root[l - 1],root[r], k);
cout << b[tmp - 1] << endl;
}
return 0;
}