POJ 2104 K-th Number 线段树

给定一个数列 a1,a2,a3......an和m个三元组表示查询,对于每个查询(i,j,k)输出 ai.....aj的升序排列中的第k个数。

我们把数列用线段树维护起来,线段树的每个节点维护了对应区间排好序的结果,计算在某个区间不超过x的数的个数,只要递归进行操作即可。

求出在某个区间里不超过x的数的个数之后,通过对x进行二分搜索来求出第k个数。

#include <iostream>
#include <vector>
#include <algorithm> 
using namespace std;
const int SIZE=1<<18-1;
int A[]={1,5,2,6,3,7,4},M=3,N;
int I[]={2,4,1};
int J[]={5,4,7};
int K[]={3,1,3};
vector<int> dat[SIZE];
//构建线段树,k是节点编号,和区间[l,r)对应 
void init(int k,int l,int r){
	if(r-l==1){
		dat[k].push_back(A[l]);
		return ;
	}
	int lch=2*k+1,rch=2*k+2;
	init(lch,l,(l+r)/2);
	init(rch,(l+r)/2,r);
	dat[k].resize(dat[lch].size()+dat[rch].size());
	//合并两个儿子数列 
	merge(dat[lch].begin(),dat[lch].end(),dat[rch].begin(),dat[rch].end(),dat[k].begin());
}
//计算[i,j)区间中不超过x的数的个数,k是节点编号和区间[l,r)对应 
int query(int i,int j,int x,int k,int l,int r){
	if(j<=l || r<=i){
		return 0;    //完全不相交 
	}
	else if(i<=l && j>=r){ //完全包含 
		return upper_bound(dat[k].begin(),dat[k].end(),x)-dat[k].begin();
	}
	else { //对儿子递归计算 
		int lc=query(i,j,x,k*2+1,l,(l+r)/2);
		int rc=query(i,j,x,k*2+2,(l+r)/2,r);
		return lc+rc;
	}
}
void solve(){
	sort(A,A+N);
	for(int i=0;i<M;i++){
		int l=I[i]-1,r=J[i],k=K[i];
		int lb=-1,ub=N-1;
		while(ub-lb>1){
			int md=(lb+ub)/2;
			int c=query(l,r,A[md],0,0,N);
			if(c>=k) ub=md;
			else lb=md;
		}
		cout<<A[ub]<<endl;
	}
}
int main()
{
	N=7;
	init(0,0,N);
	solve();
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值