最小值
时间限制:
1000 ms | 内存限制:
65535 KB
难度:
3
-
描述
-
输入N个数,M次查询。
每次查询给出一个数x。
要求:每次查询输出前x个数中第i小的数。(i为第i次查询)
你可以假设M <= N,Xi <= 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小的数,单独一行。
详细格式请参考样例。
样例输入
-
1 7 4 3 1 -4 2 8 -1000 2 1 2 6 6
样例输出
-
3 3 1 2
来源
- 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; } } }
-
Line0:T