给定一个数列 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; }