K-th Number

K-th Number

两种写法:分块、线段树(归并树)

区间种第 k 个数的特点是:①在区间中不超过 x 的数不少于 k 个②在区间中小于 x 的数有不到 k 个

分块:

所以可以对答案进行二分,然后在判断是否满足的时候利用分块进行优化。

如果直接用\(\sqrt{n}\)作为桶的大小的话,复杂度可能有些高。如果把桶的数量设置得比桶内元素略少一些,可以使得程序更加高效。

// Created by CAD on 2020/2/9.
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;

const int maxn=1e5+5;
int a[maxn],cop[maxn];
const int maxb=1000;
vector<int> b[maxb];
int blo,belo[maxn];

bool judge(int l,int r,int x,int k){
    int ans=0;
    for(int i=l;i<=min(r,belo[l]*blo);++i)
        if(x>=a[i]) ans++;
    if(belo[l]!=belo[r]){
        for(int i=(belo[r]-1)*blo+1;i<=r;++i)
            if(x>=a[i]) ans++;
    }
    for(int i=belo[l]+1;i<=belo[r]-1;++i)
        ans+=upper_bound(b[i].begin(),b[i].end(),x)-b[i].begin();
    return ans>=k;
}

int main()
{
    int n,m;    scanf("%d%d",&n,&m);
    blo=900;
    for(int i=1;i<=n;++i){
        belo[i]=(i-1)/blo+1;
        scanf("%d",&a[i]);
        b[belo[i]].push_back(a[i]);
        cop[i]=a[i];
    }
    sort(cop+1,cop+1+n);
    for(int i=1;i<=(n-1)/blo+1;++i)
        sort(b[i].begin(),b[i].end());
    while(m--){
        int i,j,k;  scanf("%d%d%d",&i,&j,&k);
        int l=1,r=n,ans=cop[n];
        while(l<=r){
            int mid=(l+r)>>1;
            if(judge(i,j,cop[mid],k)) ans=cop[mid],r=mid-1;
            else l=mid+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

归并树:

此时线段树的每一个节点保存的不是数值。而是一个序列,节点的序列是其子树上的有序点集,利用merge()函数的特性,保证了每一个节点所存序列的有序性。

// Created by CAD on 2020/2/10.
#include <cstdio>
#include <vector>
#include <algorithm>

#define lson (p<<1)
#define rson (p<<1|1)
using namespace std;

const int maxn=1e5+5;
int a[maxn],cop[maxn];
vector<int> d[maxn<<2];

void build(int s,int t,int p){
    if(s==t){
        d[p].push_back(a[s]);
        return ;
    }
    int mid=(s+t)>>1;
    build(s,mid,lson),build(mid+1,t,rson);
    d[p].resize(t-s+1);
    merge(d[lson].begin(),d[lson].end(),d[rson].begin(),d[rson].end(),d[p].begin());
}
int query(int l,int r,int x,int s,int t,int p){
    if(l<=s&&t<=r)
        return upper_bound(d[p].begin(),d[p].end(),x)-d[p].begin();
    int mid=(s+t)>>1,cnt=0;
    if(l<=mid) cnt+=query(l,r,x,s,mid,lson);
    if(r>mid) cnt+=query(l,r,x,mid+1,t,rson);
    return cnt;
}

int main()
{
    int n,m;    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)   scanf("%d",&a[i]),cop[i]=a[i];
    build(1,n,1);
    sort(cop+1,cop+1+n);
    while(m--){
        int i,j,k;  scanf("%d%d%d",&i,&j,&k);
        int l=1,r=n,ans=cop[n];
        while(l<=r){
            int mid=(l+r)>>1;
            if(query(i,j,cop[mid],1,n,1)>=k) ans=cop[mid],r=mid-1;
            else l=mid+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2020-02-09 23:39  caoanda  阅读(148)  评论(0编辑  收藏  举报