hud4417--Super Mario(划分树+二分)
求区间比K小或等于K的元素个数
View Code
1 //Accepted 4417 593MS 16388K 3445 B G++ asen11 2 #include <stdio.h> 3 #include <algorithm> 4 using namespace std; 5 #define M 100001 6 #define LL(x) ((x)<<1) 7 #define RR(x) ((x)<<1|1) 8 struct Seg_Tree{ 9 int left,right; 10 int mid() { 11 return (left + right) >> 1; 12 } 13 }tt[M*4]; 14 int len; 15 int sorted[M]; 16 int toLeft[20][M]; 17 int val[20][M]; 18 19 void build(int l,int r,int d,int idx) { 20 tt[idx].left = l; 21 tt[idx].right = r; 22 if(tt[idx].left == tt[idx].right) return ; 23 int mid = tt[idx].mid(); 24 int lsame = mid - l + 1;//lsame表示和val_mid相等且分到左边的 25 for(int i = l ; i <= r ; i ++) { 26 if(val[d][i] < sorted[mid]) { 27 lsame --;//先假设左边的数(mid - l + 1)个都等于val_mid,然后把实际上小于val_mid的减去 28 } 29 } 30 int lpos = l; 31 int rpos = mid+1; 32 int same = 0; 33 for(int i = l ; i <= r ; i ++) { 34 if(i == l) { 35 toLeft[d][i] = 0;//toLeft[i]表示[ tt[idx].left , i ]区域里有多少个数分到左边 36 } else { 37 toLeft[d][i] = toLeft[d][i-1]; 38 } 39 if(val[d][i] < sorted[mid]) { 40 toLeft[d][i] ++; 41 val[d+1][lpos++] = val[d][i]; 42 } else if(val[d][i] > sorted[mid]) { 43 val[d+1][rpos++] = val[d][i]; 44 } else { 45 if(same < lsame) {//有lsame的数是分到左边的 46 same ++; 47 toLeft[d][i] ++; 48 val[d+1][lpos++] = val[d][i]; 49 } else { 50 val[d+1][rpos++] = val[d][i]; 51 } 52 } 53 } 54 build(l,mid,d+1,LL(idx)); 55 build(mid+1,r,d+1,RR(idx)); 56 } 57 58 int query(int l,int r,int k,int d,int idx) { 59 if(l == r) { 60 return val[d][l]; 61 } 62 int s;//s表示[ l , r ]有多少个分到左边 63 int ss;//ss表示 [tt[idx].left , l-1 ]有多少个分到左边 64 if(l == tt[idx].left) { 65 s = toLeft[d][r]; 66 ss = 0; 67 } else { 68 s = toLeft[d][r] - toLeft[d][l-1]; 69 ss = toLeft[d][l-1]; 70 } 71 if(s >= k) {//有多于k个分到左边,显然去左儿子区间找第k个 72 int newl = tt[idx].left + ss; 73 int newr = tt[idx].left + ss + s - 1;//计算出新的映射区间 74 return query(newl,newr,k,d+1,LL(idx)); 75 } else { 76 int mid = tt[idx].mid(); 77 int bb = l - tt[idx].left - ss;//bb表示 [tt[idx].left , l-1 ]有多少个分到右边 78 int b = r - l + 1 - s;//b表示 [l , r]有多少个分到右边 79 int newl = mid + bb + 1; 80 int newr = mid + bb + b; 81 return query(newl,newr,k-s,d+1,RR(idx)); 82 } 83 } 84 85 void solve(int l,int r,int maxx,int L,int R)//二分查找区间第K小元素 86 { 87 if(l >= r) 88 { 89 int s = query(L,R,r,0,1); 90 if(s > maxx) 91 printf("%d\n",r-1); 92 else 93 printf("%d\n",r); 94 return ; 95 } 96 int mid = ( l + r ) / 2; 97 int s = query(L,R,mid,0,1); 98 if(s > maxx) 99 { 100 solve(l,mid,maxx,L,R); 101 } 102 else 103 { 104 solve(mid+1,r,maxx,L,R); 105 } 106 } 107 108 int main() { 109 int T,x=0; 110 scanf("%d",&T); 111 while(T --) { 112 x++; 113 int n , m; 114 scanf("%d%d",&n,&m); 115 for(int i = 1; i <= n; i++){ 116 scanf("%d",&val[0][i]); 117 sorted[i] = val[0][i]; 118 } 119 sort(sorted + 1 , sorted + n + 1); 120 build(1,n,0,1); 121 printf("Case %d:\n",x); 122 while(m --) { 123 int l,r,maxx; 124 scanf("%d%d%d",&l,&r,&maxx); 125 l++; 126 r++; 127 solve(1,r-l+1,maxx,l,r); 128 } 129 } 130 return 0; 131 }


浙公网安备 33010602011771号