题目:
n个数字,m个询问,每个询问给出(a,b,k),求区间[a,b]内的第k大数。
题解:
将线段树每个合并区间内的数据排序。
第一次二分第k大数的大小,递归找到线段树的区间[a,b],在每个区间内二分查找比k小的数字的个数。
从而找到最大的在区间内不超过k个数字比它小的的数字,将其+1就是正解。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> dat[4*101000+50];
int n,m;
void build(int l,int r,int rt){
if(l==r){
int x;
cin>>x;
dat[rt].push_back(x);
return ;
}
int mid=(l+r)/2;
build(l,mid,rt*2);
build(mid+1,r,rt*2+1);
dat[rt].resize(r-l+1);
merge(dat[rt*2].begin(),dat[rt*2].end(),dat[rt*2+1].begin(),dat[rt*2+1].end(),dat[rt].begin());
}
int query(int a,int b,int x,int l,int r,int rt){
if(l>=a&&r<=b) return upper_bound(dat[rt].begin(),dat[rt].end(),x)-dat[rt].begin();
int mid=(l+r)/2;
int ret=0;
// cout<<l<<' '<<mid<<' '<<r<<endl;
if(mid>=a) ret+=query(a,b,x,l,mid,rt*2);
if(mid<b) ret+=query(a,b,x,mid+1,r,rt*2+1);
return ret;
}
int binsearch(int a,int b,int k){
int l=-1e9-7;
int r=1e9+7;
while(r-l>1){
int mid=(l+r)/2;
int ret=query(a,b,mid,1,n,1);
//cout<<l<<' '<<r<<' '<<mid<<' '<<ret<<endl;
if(ret<k) l=mid;
else r=mid;
}
return l+1;
}
/*
7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3
*/
int main(){
cin>>n>>m;
build(1,n,1);
while(m--){
int a,b,x;
cin>>a>>b>>x;
cout<<binsearch(a,b,x)<<endl;
}
}
本文介绍了一种使用线段树和二分搜索解决区间查询问题的方法,具体为求解给定区间内的第k大数。通过构建线段树并进行排序,再结合二分搜索来高效地定位目标值。

536

被折叠的 条评论
为什么被折叠?



