区间第K大(POJ-2104)

可持久化线段树不是一颗完全二叉树,所以不能用层次序编号,而应该直接记录每个节点的左、右子节点的编号。可持久化线段树维护了每次操作后线段树的历史形态。
下面举个简单的例子来理解一下:
以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;
}
发布了40 篇原创文章 · 获赞 6 · 访问量 1418

猜你喜欢

转载自blog.csdn.net/qq_43321732/article/details/103926813
今日推荐