POJ 2104

本文介绍了一种使用线段树和二分搜索解决区间查询问题的方法,具体为求解给定区间内的第k大数。通过构建线段树并进行排序,再结合二分搜索来高效地定位目标值。

题目:

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;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值