POJ 2104 K-th Number 主席树

题意:

给出\(n(1 \leq n \leq 10^5)\)个数字和\(m(1 \leq m \leq 5000)\)个询问。
每次询问形式如下:

  • \(l \, r \, k\)表示询问区间\([l,r]\)从小到大排序后第\(k\)个数字的大小。

分析:

推荐这篇主席树的教程,里面的图片十分简洁明了,一图胜千言。
主席树的本质就是可持久化线段树,为了节省空间,相邻两棵树共用了相同的的区间节点(也就是数据不发生变换的区间)。
仅对于数据发生变化的区间新建节点来更新维护信息。

区间维护的信息是值域上数字出现的次数,所以我们先把输入数据离散化一下。
查询第\(k\)小的时候类似于\(BST\)中的名次树,先查询区间\([l,r]\)中数字的个数\(cnt\)\(m=\frac{l+r}{2}\)是区间的中点。

  • 如果\(cnt \geq k\),那么第\(k\)小的值一定在左区间\([l, m]\)中,递归求解左区间的第\(k\)
  • 否则,第\(k\)小的值一定在右区间\([m, r]\)中,递归求解右区间的第\(k-cnt\)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 100000 + 10;

struct Node
{
	int lch, rch, sum;
};

int sz;
Node T[maxn << 5];

int newnode() {
	T[sz].lch = T[sz].rch = T[sz].sum = 0;
	return sz++;
}

int build(int L, int R) {
	int rt = newnode();
	if(L == R) return rt;
	int M = (L + R ) / 2;
	T[rt].lch = build(L, M);
	T[rt].rch = build(M + 1, R);
	return rt;
}

int update(int pre, int L, int R, int p) {
	int rt = newnode();
	T[rt].lch = T[pre].lch;
	T[rt].rch = T[pre].rch;
	T[rt].sum = T[pre].sum + 1;
	if(L == R) return rt;
	int M = (L + R) / 2;
	if(p <= M) T[rt].lch = update(T[pre].lch, L, M, p);
	else T[rt].rch = update(T[pre].rch, M + 1, R, p);
	return rt;
}

int query(int s, int t, int L, int R, int k) {
	if(L == R) return L;
	int M = (L + R) / 2;
	int cnt = T[T[t].lch].sum - T[T[s].lch].sum;
	if(cnt >= k) return query(T[s].lch, T[t].lch, L, M, k);
	else return query(T[s].rch, T[t].rch, M+1, R, k - cnt);
}

int n, m;
int a[maxn], b[maxn], tot, root[maxn];

int main()
{
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++) {
		scanf("%d", a + i);
		b[i] = a[i];
	}
	sort(b + 1, b + 1 + n);
	tot = unique(b + 1, b + 1 + n) - (b + 1);

	sz = 0;
	root[0] = build(1, tot);
	for(int i = 1; i <= n; i++) {
		int id = lower_bound(b + 1, b + 1 + tot, a[i]) - b;
		root[i] = update(root[i - 1], 1, tot, id);
	}

	while(m--) {
		int l, r, k; scanf("%d%d%d", &l, &r, &k);
		int ans = query(root[l - 1], root[r], 1, tot, k);
		printf("%d\n", b[ans]);
	}

	return 0;
}
posted @ 2016-03-15 15:32  AOQNRMGYXLMV  阅读(158)  评论(0编辑  收藏  举报