Time Limit: 6000MS | Memory Limit: 65536K | |
Total Submissions: 14029 | Accepted: 4273 |
Description
Input
Output
Sample Input
7 2 1 5 2 6 3 7 4 1 5 3 2 7 1
Sample Output
3 2
Source
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; //***************************************************************** const int MAXN=100001+100; int tree[30][MAXN];//表示每层每个位置的值 int sorted[MAXN];//已经排序的数 int toleft[30][MAXN];//toleft[p][i]表示第p层从1到i有多少个数分入左边 //创建划分树 //时间复杂度为O(N*log(N)) void build(int l,int r,int dep) { int i; if(l==r)return; int mid=(l+r)>>1; int same=mid-l+1;//表示等于中间值而且被分入左边的个数 for(i=l;i<=r;i++) if(tree[dep][i]<sorted[mid]) same--; int lpos=l; int rpos=mid+1; for(i=l;i<=r;i++) { if(tree[dep][i]<sorted[mid])//比中间的数小,分入左边 tree[dep+1][lpos++]=tree[dep][i]; else if(tree[dep][i]==sorted[mid]&&same>0) { tree[dep+1][lpos++]=tree[dep][i]; same--; } else //比中间值大分入右边 tree[dep+1][rpos++]=tree[dep][i]; toleft[dep][i]=toleft[dep][l-1]+lpos-l;//从1到i放左边的个数 } build(l,mid,dep+1); build(mid+1,r,dep+1); } //查询区间第k小的数,[L,R]是大区间,[l,r]是要查询的小区间 //时间复杂度为O(log(N)) int query(int L,int R,int l,int r,int dep,int k) { if(l==r)return tree[dep][l]; int mid=(L+R)>>1; int cnt=toleft[dep][r]-toleft[dep][l-1];//[l,r]中位于左边的个数 if(cnt>=k) { //L+要查询的区间前被放在左边的个数 int newl=L+toleft[dep][l-1]-toleft[dep][L-1]; //左端点加上查询区间会被放在左边的个数 int newr=newl+cnt-1; return query(L,mid,newl,newr,dep+1,k); } else { int newr=r+toleft[dep][R]-toleft[dep][r]; int newl=newr-(r-l-cnt); return query(mid+1,R,newl,newr,dep+1,k-cnt); } } //***************************************************************** int main() { int n,m,i,r,l,k; while(~scanf("%d%d",&n,&m)) { memset(toleft,0,sizeof(toleft)); for(i=1;i<=n;i++) { scanf("%d",&tree[0][i]); sorted[i]=tree[0][i]; } sort(sorted+1,sorted+n+1); build(1,n,0); while(m--) { scanf("%d%d%d",&l,&r,&k); printf("%d\n",query(1,n,l,r,0,k)); } } return 0; }