HDU 4417 Super Mario(划分树)
题目大意
给你 n(1<=n<=10^5) 个数,m(1<=m<=10^5) 个询问,每个询问的格式如下
L R H:从第 L 个数到第 R 个数中,小于等于 H 的数有多少个
做法分析
建立划分树
每次 query 的时候,二分答案即可,即二分这个区间中有多少个小于等于 H 的数
参考代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int N=100006; 9 10 struct devided_tree 11 { 12 int val[20][N], f[20][N], sorted[N]; 13 14 void build(int L, int R, int deep) 15 { 16 if(L==R) return; 17 int mid=(L+R)>>1; 18 int midVal=sorted[mid], tot=mid-L+1; 19 for(int i=L; i<=R; i++) if(val[deep][i]<midVal) tot--; 20 int sL=L, sR=mid+1; 21 for(int i=L; i<=R; i++) 22 { 23 f[deep][i]=(i==L)?0:f[deep][i-1]; 24 if(val[deep][i]<midVal || (val[deep][i]==midVal && tot)) 25 { 26 val[deep+1][sL++]=val[deep][i]; 27 f[deep][i]++; 28 if(val[deep][i]==midVal) tot--; 29 } 30 else val[deep+1][sR++]=val[deep][i]; 31 } 32 build(L, mid, deep+1), build(mid+1, R, deep+1); 33 } 34 35 int query(int L, int R, int st, int en, int k, int deep) 36 { 37 if(st==en) return val[deep][st]; 38 int mid=(L+R)>>1; 39 int L1=(L==st)?0:f[deep][st-1]; 40 int L2=f[deep][en]-L1; 41 if(k<=L2) return query(L, mid, L+L1, L+L1+L2-1, k, deep+1); 42 int R1=(st-1-L+1)-L1; 43 int R2=(en-st+1)-L2; 44 return query(mid+1, R, mid+1+R1, mid+1+R1+R2-1, k-L2, deep+1); 45 } 46 } tree; 47 48 int main() 49 { 50 int t, n, m; 51 scanf("%d", &t); 52 for(int ca=1; ca<=t; ca++) 53 { 54 scanf("%d%d", &n, &m); 55 for(int i=0; i<n; i++) 56 { 57 scanf("%d", &tree.val[0][i]); 58 tree.sorted[i]=tree.val[0][i]; 59 } 60 sort(tree.sorted, tree.sorted+n); 61 tree.build(0, n-1, 0); 62 printf("Case %d:\n", ca); 63 for(int i=0, a, b, c; i<m; i++) 64 { 65 scanf("%d%d%d", &a, &b, &c); 66 int L=1, R=b-a+1; 67 while(L<R) 68 { 69 int mid=(L+R)>>1; 70 int keyVal=tree.query(0, n-1, a, b, mid, 0); 71 if(keyVal<=c) L=mid+1; 72 else R=mid; 73 } 74 if(tree.query(0, n-1, a, b, L, 0)>c) L--; 75 printf("%d\n", L); 76 } 77 } 78 return 0; 79 }
AC通道