现在的位置: 首页 > 综合 > 正文

可持久化线段树入门题 hdu2665 求区间第k小的数

2014年07月18日 ⁄ 综合 ⁄ 共 1205字 ⁄ 字号 评论关闭

注意:这题题意写错了,不是区间第k大,而是区间第k小, WA了一地,看了discuss才知道,坑啊

参考了clj的论文可持久化数据结构研究,具体做法论文里很明确。

其实思想还是建多颗线段树,只是把这些线段树数据不相同的部分另外建了一些节点。

对于m个询问,每次要建log(n)的节点,需要 n*2+mlog(n)的内存,这题写得不好数组就开不下了

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define lson l, m, ls[rt]
#define rson m+1, r, rs[rt]
#define Mid int m = l+r>>1
const int maxn = 100005;
int ls[maxn*20], rs[maxn*20], sum[maxn*20], tot;
int root[maxn];
void build(int l, int r, int &rt) {
	rt = ++tot;
	sum[rt] = 0;
	if(l == r) return;
	Mid;
	build(lson);
	build(rson);
}

void update(int o, int p, int v, int l, int r, int &rt) {
	rt = ++tot;
	sum[rt] = sum[o] + v;
	ls[rt] = ls[o];
	rs[rt] = rs[o];
	if(l == r) return;
	Mid;
	if(p <= m) update(ls[o], p, v, lson);
	else update(rs[o], p, v, rson);
}

int query(int o, int k, int l, int r, int rt) {   //o-->rt 第k小的数
	if(l == r) return l;
	Mid;
	int res = sum[ls[rt]] - sum[ls[o]];
	if(k <= res) return query(ls[o], k, lson);
	else return query(rs[o], k-res, rson);
}
int a[maxn], b[maxn];
int main() {
	int i, j, cas;
	int n, m;
	scanf("%d", &cas);
	while(cas--) {
		scanf("%d%d", &n, &m);
		for(i = 0; i < n; i++) {
			scanf("%d", &a[i]);
			b[i] = a[i];
		}
		sort(b, b+n);
		int sz = unique(b, b+n)-b;
		tot = 0;
		build(1, sz, root[0]);
		for(i = 0; i < n; i++) {
			j = lower_bound(b, b+sz, a[i])-b+1;
			update(root[i], j, 1, 1, sz, root[i+1]);
		}
		while(m--) {
			int x, y, z;
			scanf("%d%d%d", &x, &y, &z);
			printf("%d\n", b[query(root[x-1], z, 1, sz, root[y])-1]);
		}
	}
}

抱歉!评论已关闭.