cogs930

找第k小的数

输入文件:kth.in 输出文件:kth.out 简单对比
时间限制:1 s 内存限制:256 MiB

【题目描述】

看到很短的题目会让人心情愉悦,所以给出一个长度为N的序列A1,A2,A3,...,AN,
现在有M个询问,每个询问都是Ai...Aj中第k小的数等于多少。

【输入格式】

第一行两个正整数N,M。
第二行N个数,表示序列A1,A2,...,AN。
紧着的M行,每行三个正整数i,j,k(k≤j-i+1),表示
询问Ai...Aj中第k小的数等于多少。

【输出格式】

共输出M行,第i行输出第i个询问的答案。

【样例输入1】

4 3
4 1 2 3
1 3 1
2 4 3
1 4 4 

【样例输出1】

1
3
4

【样例输入2】

5 5
4 2 9 9 10
1 3 1
2 4 3
1 4 4
3 5 2
2 5 2

【样例输出2】

2
9
9
9
9

【提示】

询问区间的第k小值并非严格第k小,例如样例2中第4个询问,询问3到5中第2小的数,
答案输出9,并不是严格第2小的10。

在50%的数据中,1<=N<=10,000,1<=M<=10,000,A[i]<=100,000;
在100%的数据中,1<=N<=100,000,1<=M<=100,000,A[i]<=1,000,000;


原本是要刷一个CDQ分支的题目,可是做不出来。后来看题解才知道是整体二分!也就学习了一下。
整体二分,简单来说,就是把多个询问进行一起二分答案!
比CDQ分治要难!


#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int maxm=1e6+10;
int n,m;
struct num
{
    int p,x;
}a[maxn],a1[maxn],a2[maxn];
struct que
{
    int l,r,k,id;
}q[maxm],q1[maxm],q2[maxm];
int sm[maxm];
void add(int pos,int x)
{
    for(int i=pos;i<=1000000;i+=i&-i)sm[i]+=x;
}
int query(int pos)
{
    int ret=0;
    for(int i=pos;i;i-=i&-i)ret+=sm[i];
    return ret;
}
int ans[maxn];
void solove(int l,int r,int al,int ar,int ql,int qr)
{
    if(l>r||ql>qr||al>ar)return;
    if(l==r)
    {
        for(int i=ql;i<=qr;++i)ans[q[i].id]=l;
        return ;
    }
    int mid=(l+r)>>1;
    int a1c=0,a2c=0;
    for(int i=al;i<=ar;++i)
    {
        if(a[i].x<=mid)
        {
            add(a[i].p,1);a1[al+a1c]=a[i];a1c++;
        }
        else a2[al+a2c]=a[i],++a2c;
    }
    int q1c=0,q2c=0;
    for(int i=ql;i<=qr;++i)
    {
        int tp=query(q[i].r)-query(q[i].l-1);
        if(tp>=q[i].k)q1[ql+q1c]=q[i],++q1c;
        else q[i].k-=tp,q2[ql+q2c]=q[i],++q2c;
    }
    for(int i=al;i<al+a1c;++i)a[i]=a1[i];
    for(int i=al+a1c;i<=ar;++i)a[i]=a2[i-a1c];
    for(int i=ql;i<ql+q1c;++i)q[i]=q1[i];
    for(int i=ql+q1c;i<=qr;++i)q[i]=q2[i-q1c];
    for(int i=al;i<al+a1c;++i)add(a1[i].p,-1);
    solove(l,mid,al,al+a1c-1,ql,ql+q1c-1);
    solove(mid+1,r,al+a1c,ar,ql+q1c,qr);
}
int mx=-1,mn=1000001;
int main()
{
    freopen("kth.in","r",stdin);
    freopen("kth.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&a[i].x),a[i].p=i;
        mx=max(mx,a[i].x);
        mn=min(mn,a[i].x);
    }
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k);
        q[i].id=i;
    }
    solove(mn,mx,1,n,1,m);
    for(int i=1;i<=m;++i)printf("%d\n",ans[i]);
    return 0;
}

posted on 2021-11-05 21:57  gryzy  阅读(24)  评论(0编辑  收藏  举报

导航