最小值(划分树)

来源:互联网 发布:js把date转换成字符串 编辑:程序博客网 时间:2024/06/06 18:41

最小值

时间限制:1000 ms  |  内存限制:65535 KB
难度:3
描述

输入N个数,M次查询。

每次查询给出一个数x

 

要求:每次查询输出前x个数中第i小的数。(i为第i次查询)

你可以假设M  <= NXi <= Xi+1 <= Xi+2 <= ……. <= Xm (Xm <= N).


输入
Line0:T
Line1: N,M
Line2…LineN+1:num1,......,numN
LineN+2…LineN+2+M:x1,……,xM

N < 30000, num < 2000000000
输出
每次查询输出前i小的数,单独一行。
详细格式请参考样例。
样例输入
17 43 1 -4 2 8 -1000 21 2 6 6
样例输出
3312
来源
STL
上传者
ACM_钟诗俊

#include <iostream>#include <string.h>#include <stdio.h>#include <algorithm>#define maxn 100010#define mid ((l+r)>>1)using namespace std;int t[20][maxn],sum[20][maxn];int a[maxn],as[maxn];//以下为查找区间第k小划分树void build(int p,int l,int r){    int lm=0,i,ls=l,rs=mid+1;//lm表示应被放入左子树且与中位数相等的数有多少个,ls为左子树的起始位置,rs为右子树的起始位置    for(i=mid;i>=l;i--) //求lm    {        if(as[i]==as[mid])        lm++;        else        break;    }    for(i=l;i<=r;i++)    {        if(i==l)//这里要特殊讨论        sum[p][i]=0;        else        sum[p][i]=sum[p][i-1];        if(t[p][i]==as[mid])//若与中位数相等则判断是否应该被放入左子树        {            if(lm)            {                lm--;                sum[p][i]++;                t[p+1][ls++]=t[p][i];            }            else            t[p+1][rs++]=t[p][i];        }        else if(t[p][i]<as[mid])//查找区间第K大即为>        {            sum[p][i]++;            t[p+1][ls++]=t[p][i];        }        else        t[p+1][rs++]=t[p][i];    }    if(l==r)    return;    build(p+1,l,mid);    build(p+1,mid+1,r);}int query(int p,int l,int r,int ql,int qr,int k){    int s,ss;//s表示l到ql-1的区间内放入左子树的个数,ss表示区间[ql,qr]被放入左子树的个数    if(l==r)//找到所求的数    return t[p][l];    if(ql==l)    s=0,ss=sum[p][qr];    else    s=sum[p][ql-1],ss=sum[p][qr]-s;    if(k<=ss)//要找的数在左子树中    return query(p+1,l,mid,l+s,l+sum[p][qr]-1,k);    else//要找的数在右子树中    return query(p+1,mid+1,r,mid+1-l+ql-s,mid+1-l+qr-sum[p][qr],k-ss);}int main(){    int t1,n,m,i,b;    cin>>t1;    while(t1--)    {        cin>>n>>m;        for(i=1;i<=n;i++)        {            cin>>as[i];            t[0][i]=as[i];        }        sort(as+1,as+1+n);        build(0,1,n);        for(i=1;i<=m;i++)        {            scanf("%d",&b);            cout<<query(0,1,n,1,b,i)<<endl;        }    }}



0 0