K-th Number

K-th Number

此处输入链接的描述

题意

给定一个序列\(a1,a2,a3...,an\),和m个三元组表示的查询.对于每个查询\((i,j,k)\),输出\(ai,ai+1,...aj\)的升序排列中的第\(k\)个数。
思路:
平方分割;
如果\(x\)是第\(k\)个数,那么有

  • 在区间中不超过x的数不少于k个
  • 在区间中小于x的数有不到k个
    那分整个数来判断当前的数是否符合区间中的第k小数,因为二分的是整个区间所以假设当前二分的数字比要求的数字大并且不在当前区间中那么因为二分是取最小的符合要求的,所以不会选到这个不符合要求的数,如果当前数\(s\)小于所要求的数并且符合为第k小的数且不在要求的区间内,这样的数是不存在的,假设符合要求的数是\(t\),那么在区间中有k个数小于等于\(t\)这些数中包括他自己,所以如果是\(s\)的话他就不可能有k个数小于等于\(s\),所以可以整体二分.
    分块处理:
  • 对于完全包含在区间内的桶,用二分搜索法计算.
  • 对于所在的桶不完全包含在区间内的元素,逐个检查.
    复杂度分析见白书.
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<math.h>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
const LL mod = 1e9+7;
int a[100005];
vector<int>vec[100005];
int num[100005];
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char Getchar()
{
    if(head==tail)
    {
        int l=fread(buffer,1,BufferSize,stdin);
        tail=(head=buffer)+l;
    }
    return *head++;
}
inline int read()
{
    int x=0,f=1;
    char c=Getchar();
    for(; !isdigit(c); c=Getchar()) if(c=='-') f=-1;
    for(; isdigit(c); c=Getchar()) x=x*10+c-'0';
    return x*f;
}
int main(void)
{
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i = 0; i < n; i++)
        scanf("%d",&a[i]);
    int c = 1000;
    int cn = 1;
    for(int i = 0; i < n; i++)
    {
        num[i] = a[i];
        if(i < c*cn)
            vec[cn-1].push_back(a[i]);
        else
        {
            cn++;
            vec[cn-1].push_back(a[i]);
            sort(vec[cn-2].begin(),vec[cn-2].end());
        }
    }
    sort(vec[cn-1].begin(),vec[cn-1].end());
    sort(num,num+n);
    a[n] = 1e9;
    for(int i = 0; i < m; i++)
    {
        int ll,rr,k;
        scanf("%d",&ll),scanf("%d",&rr),scanf("%d",&k);
        ll--,rr--;
        int l = 0,r = n-1;
        int ask = 0;
        while(l <= r)
        {
            int mid = (l+r)/2;
            int d = num[mid];
            int tl  = ll,tr = rr,sum = 0;
            while(tl <= tr&&tl%c!=0)if(a[tl++] <= d)sum++;
            while(tl <= tr&&tr%c!=0)if(a[tr--] <= d)sum++;
            if(a[tr] <= d&&tl <= tr)sum++;
            tr--;
            while(tl <= tr)
            {
                int u = tl/c;
                int lll = 0,rrr = vec[u].size()-1;
                int id = -1;
                while(lll <= rrr)
                {
                    int ic = (lll+rrr)/2;
                    if(vec[u][ic] <= d)
                    {
                        id = ic;
                        lll = ic + 1;
                    }
                    else rrr = ic - 1;
                }
                sum += id + 1;
                tl += c;
            }
            if(sum >= k)
                ask = mid,r = mid - 1;
            else l = mid + 1;
        }
        printf("%d\n",num[ask]);
    }
    return 0;
}
posted @ 2017-05-18 15:08  sCjTyC  阅读(233)  评论(0编辑  收藏  举报