【题意】给定N个数,M个询问,每个询问l,r,k,求[l,r]区间内第k大的数是多少。
【分析】区间第k大数,很多方法都可以做。这里是静态询问,没有修改点的值。划分树练手。


1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h> 4 #include<algorithm> 5 6 using namespace std; 7 8 #define maxn 100010 9 10 int len; 11 int sorted[maxn]; 12 int toLeft[20][maxn],val[20][maxn]; 13 void build(int d, int l, int r) 14 { 15 if (l == r) 16 return ; 17 int m = (l + r)>>1; 18 int lsame = m - l + 1; 19 20 for (int i=l;i<=r;i++){ 21 if (val[d][i] < sorted[m]){ 22 lsame --; 23 } 24 } 25 int lpos = l; 26 int rpos = m + 1; 27 int same = 0; 28 for (int i=l;i<=r;i++){ 29 if (i == l){ 30 toLeft[d][i] = 0; 31 }else { 32 toLeft[d][i] = toLeft[d][i-1]; 33 } 34 if (val[d][i] < sorted[m]){ 35 toLeft[d][i]++; 36 val[d+1][lpos++] = val[d][i]; 37 }else if (val[d][i] > sorted[m]){ 38 val[d+1][rpos++] = val[d][i]; 39 }else{ 40 if (same < lsame){ 41 same++; 42 toLeft[d][i]++; 43 val[d+1][lpos++] = val[d][i]; 44 }else{ 45 val[d+1][rpos++] = val[d][i]; 46 } 47 } 48 } 49 build(d+1, l, m); 50 build(d+1, m+1, r); 51 } 52 53 54 int query(int L, int R, int k, int d, int l,int r) 55 { 56 /**/ 57 if (l == r) 58 return val[d][l]; 59 int s;//s表示[L,R]内有多少个被分到了左区间 60 int ss;//ss表示[l,L-1]有多少个被分到了左区间 61 int m = (l + r)>>1; 62 if (L == l){ 63 s = toLeft[d][R]; 64 ss = 0; 65 }else{ 66 s = toLeft[d][R] - toLeft[d][L-1]; 67 ss = toLeft[d][L-1]; 68 } 69 if (s >= k){//有多余k个分到左边,显然去左儿子区间找第k个 70 return query(l+ss, l+ss+s-1,k,d+1,l,m); 71 }else{ 72 return query(m+L-l-ss+1, m-l-ss+R-s+1,k-s,d+1,m+1,r); 73 } 74 } 75 int n, m; 76 int main() 77 { 78 while (scanf("%d%d",&n,&m)==2) 79 { 80 for (int i=1;i<=n;i++) 81 { 82 scanf("%d",&val[1][i]); 83 sorted[i] = val[1][i]; 84 } 85 sort(sorted+1,sorted+1+n); 86 build(1,1,n); 87 while (m--) 88 { 89 int l,r,k; 90 scanf("%d%d%d",&l,&r,&k); 91 if (l > r) 92 swap(l, r); 93 printf("%d\n",query(l,r,k,1,1,n)); 94 } 95 } 96 return 0; 97 }
本文详细介绍了如何使用划分树解决区间第k大数的问题,通过实例代码讲解了算法的具体实现过程,适用于静态询问场景。
490

被折叠的 条评论
为什么被折叠?



