划分树
1 /* 2 HDU 2665 Kth number 3 划分树 4 5 6 */ 7 8 9 #include<stdio.h> 10 #include<iostream> 11 #include<string.h> 12 #include<algorithm> 13 using namespace std; 14 15 const int MAXN=100010; 16 int tree[30][MAXN];//表示每层每个位置的值 17 int sorted[MAXN];//已经排序的数 18 int toleft[30][MAXN];//toleft[p][i]表示第i层从1到i有多少个数分入左边 19 20 void build(int l,int r,int dep) 21 { 22 if(l==r)return; 23 int mid=(l+r)>>1; 24 int same=mid-l+1;//表示等于中间值而且被分入左边的个数 25 for(int i=l;i<=r;i++) 26 if(tree[dep][i]<sorted[mid]) 27 same--; 28 int lpos=l; 29 int rpos=mid+1; 30 for(int i=l;i<=r;i++) 31 { 32 if(tree[dep][i]<sorted[mid])//比中间的数小,分入左边 33 tree[dep+1][lpos++]=tree[dep][i]; 34 else if(tree[dep][i]==sorted[mid]&&same>0) 35 { 36 tree[dep+1][lpos++]=tree[dep][i]; 37 same--; 38 } 39 else //比中间值大分入右边 40 tree[dep+1][rpos++]=tree[dep][i]; 41 toleft[dep][i]=toleft[dep][l-1]+lpos-l;//从1到i放左边的个数 42 43 } 44 build(l,mid,dep+1); 45 build(mid+1,r,dep+1); 46 47 } 48 49 50 //查询区间第k大的数,[L,R]是大区间,[l,r]是要查询的小区间 51 int query(int L,int R,int l,int r,int dep,int k) 52 { 53 if(l==r)return tree[dep][l]; 54 int mid=(L+R)>>1; 55 int cnt=toleft[dep][r]-toleft[dep][l-1];//[l,r]中位于左边的个数 56 if(cnt>=k) 57 { 58 //L+要查询的区间前被放在左边的个数 59 int newl=L+toleft[dep][l-1]-toleft[dep][L-1]; 60 //左端点加上查询区间会被放在左边的个数 61 int newr=newl+cnt-1; 62 return query(L,mid,newl,newr,dep+1,k); 63 } 64 else 65 { 66 int newr=r+toleft[dep][R]-toleft[dep][r]; 67 int newl=newr-(r-l-cnt); 68 return query(mid+1,R,newl,newr,dep+1,k-cnt); 69 } 70 } 71 72 73 int main() 74 { 75 //freopen("in.txt","r",stdin); 76 //freopen("out.txt","w",stdout); 77 int T; 78 int n,m; 79 int s,t,k; 80 scanf("%d",&T); 81 while(T--) 82 { 83 scanf("%d%d",&n,&m); 84 memset(tree,0,sizeof(tree));//这个必须 85 for(int i=1;i<=n;i++)//从1开始 86 { 87 scanf("%d",&tree[0][i]); 88 sorted[i]=tree[0][i]; 89 } 90 sort(sorted+1,sorted+n+1); 91 build(1,n,0); 92 while(m--) 93 { 94 scanf("%d%d%d",&s,&t,&k); 95 printf("%d ",query(1,n,s,t,0,k)); 96 } 97 } 98 return 0; 99 }