求区间第k小值~
详细注释见代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #define M 100005 6 using namespace std; 7 int sorted[M],toleft[30][M],tree[30][M],m,n; 8 void read() 9 { 10 for(int i=1;i<=m;i++) 11 { 12 scanf("%d",&sorted[i]); 13 tree[0][i]=sorted[i]; 14 } 15 sort(sorted+1,sorted+1+m); 16 } 17 void create(int l,int r,int d) 18 { 19 if(l==r) return; 20 int mid=(l+r)>>1; 21 int same=mid-l+1;//左子树中的数字个数 22 for(int i=l;i<=r;i++) 23 if(tree[d][i]<sorted[mid]) same--;//此时same成为和中位数相等的位于左子树的数字个数 24 25 int ls=l,rs=mid+1;//分别为左右区间的起点 26 for(int i=l;i<=r;i++) 27 { 28 int fg=0; 29 if((tree[d][i]<sorted[mid])||(tree[d][i]==sorted[mid]&&same>0))//将符合条件的数分到左子树 30 { 31 fg=1; 32 tree[d+1][ls++]=tree[d][i]; 33 if(tree[d][i]==sorted[mid]) same--;//有些与中位数相同的数分到左子树,剩下的分到右子树 34 } 35 else tree[d+1][rs++]=tree[d][i];//分到右子树 36 toleft[d][i]=toleft[d][i-1]+fg;//toleft[d][i]表示从l到i区间中有多少数分到了其左子树中 37 } 38 //递归建树 39 create(l,mid,d+1); 40 create(mid+1,r,d+1); 41 } 42 int query(int ql,int qr,int k,int l,int r,int d) 43 { 44 if(ql==qr) return tree[d][ql]; 45 int mid=(l+r)>>1; 46 int x=toleft[d][ql-1]-toleft[d][l-1];//位于ql(待求区间左端点)(不包括ql)左边的放于左子树中的数字个数 47 int y=toleft[d][qr]-toleft[d][l-1];//位于qr(待求区间右端点)(包括qr)左边的放于左子树中的数字个数 48 int ry=qr-l+1-y;//位于qr(包含qr)的在右子树中的数字个数 49 int cnt=y-x;//位于区间[ql,qr]中的在左子树中的数字个数 50 int rx=ql-l-x;//位于ql左边(不包含ql)的在右子树中的数字个数 51 if(cnt>=k) return query(l+x,l+y-1,k,l,mid,d+1); 52 else return query(mid+rx+1,mid+ry,k-cnt,mid+1,r,d+1); 53 } 54 void go() 55 { 56 create(1,m,0); 57 for(int i=1,a,b,k;i<=n;i++) 58 { 59 scanf("%d%d%d",&a,&b,&k); 60 int ans=query(a,b,k,1,m,0); 61 printf("%d\n",ans); 62 } 63 } 64 int main() 65 { 66 while(scanf("%d%d",&m,&n)!=EOF) 67 { 68 read(); 69 go(); 70 } 71 return 0; 72 }