区间第k大有很多种求法,最近在刷线段树,所以用线段树结合STL写了一个。
线段树的建立类似与归并树:
可以通过线段数快速求得某个区间大于或者小于某个数的数的个数。
然后二分答案,直到结果为k为止。
poj 2104就是一道求区间第k大的题目
下面我的代码:
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#define maxn 1000005
using namespace std;
vector <int> dat[maxn*2];
int num[maxn],A[maxn];
int build (int o,int L,int R){
if (L==R){
dat[o].push_back(num[L]);
}
else {
int M=L+(R-L)/2;
build (o*2,L,M);
build (o*2+1,M+1,R);
dat[o].resize(R-L+1);
merge(dat[o*2].begin(),dat[o*2].end(),dat[o*2+1].begin(),dat[o*2+1].end(),dat[o].begin());
}
return 0;
}
int c,y1,y2,x;
int query (int o,int L,int R){
if (y1<=L&&y2>=R){
c+=upper_bound(dat[o].begin(),dat[o].end(),x)-dat[o].begin();
}
else {
int M=L+(R-L)/2;
if (y1<=M) query(o*2,L,M);
if (y2>M) query(o*2+1,M+1,R);
}
return 0;
}
int n,m;
int solve(int l,int r,int k){
int lb=1,rb=n;
y1=l,y2=r;
while (rb>lb){
int Mid=lb+(rb-lb)/2;
x=A[Mid];
c=0;
query(1,1,n);
if (c>=k) rb=Mid;
else lb=Mid+1;
//cout<<c<<" "<<x<<endl;
}
printf("%d\n",A[rb]);
}
int main (){
while (~scanf("%d%d",&n,&m)){
for (int i=1;i<=n;i++){
scanf("%d",&num[i]);
A[i]=num[i];
}
build(1,1,n);
sort(A+1,A+n+1);
for (int i=0;i<m;i++){
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
solve(l,r,k);
}
}
return 0;
}