[POJ 2104] K-th Number [划分树]

本文介绍了一种解决区间查找第k大数的问题,并通过划分树的数据结构进行高效实现。文中提供了完整的C++代码示例,包括划分树的构建与查询过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

求区间第k大数...昨天块状链表没过...今天正经的用划分树做下..

顺带一个划分树教程

tip: build那里我觉得 if (l==r) return;这句话写在最开始就好,事实上我这么写的也过了..不知道他为什么放到后边..


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>

using namespace std;

int n,m;
int a[100010],b[100010];
int tree[20][100010];
int num[20][100010];

void build(int i,int l,int r) {
	//printf("== %d %d %d\n",i,l,r);
	if (l==r) return;
	int t=(l+r)/2,e=t-l+1,j,pl=l,pr=t+1;
	for (j=l;j<=t;j++) if (b[j]<b[t]) e--;
	for (j=l;j<=r;j++) {
		num[i][j]=(j==l)?0:num[i][j-1];
		if (tree[i][j]<b[t]) {
			num[i][j]++;
			tree[i+1][pl++]=tree[i][j];
		} else if (tree[i][j]>b[t]) {
			tree[i+1][pr++]=tree[i][j];
		} else if (e>0) {
			e--;
			tree[i+1][pl++]=tree[i][j];
			num[i][j]++;
		} else {
			tree[i+1][pr++]=tree[i][j];
		}
	}
	build(i+1,l,t);
	build(i+1,t+1,r);
}

int get(int i,int l,int r,int ql,int qr,int k) {
	if (l==r) return tree[i][l];
	int t=(l+r)/2,s=(l==ql)?0:num[i][ql-1],ss=num[i][qr]-s;
	if (k<=ss) 
		return get(i+1,l,t,l+s,l+s+ss-1,k);
	else 
		return get(i+1,t+1,r,ql+t-l+1-s,qr+t-l+1-s-ss,k-ss);
}

int main() {
	int x,y,z,i;
	scanf("%d%d",&n,&m);
	for (i=1;i<=n;i++) {
		scanf("%d",&a[i]);
		tree[0][i]=b[i]=a[i];
	}
	sort(b+1,b+n+1);
	build(0,1,n);
	for (i=0;i<m;i++) {
		scanf("%d%d%d",&x,&y,&z);
		printf("%d\n",get(0,1,n,x,y,z));
	}
	/*
	for (i=0;i<5;i++) {
		for (int j=1;j<=n;j++) printf("%d ",tree[i][j]);
		printf("\n");
	}
	for (i=0;i<5;i++) {
		for (int j=1;j<=n;j++) printf("%d ",num[i][j]);
		printf("\n");
	}
	*/
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值