题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417
题意:给定n个数和q次询问,每次询问[l,r]区间内不比k大的数字的个数。
直接上归并树,每次查询直接查区间内小于等于k的数的个数,二分即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define lrt rt << 1 5 #define rrt rt << 1 | 1 6 const int maxn = 100100; 7 int n, q, a[maxn]; 8 vector<int> seg[maxn<<2]; 9 10 void build(int l, int r, int rt) { 11 if(l == r) { 12 seg[rt].clear(); 13 seg[rt].push_back(a[l]); 14 return; 15 } 16 int mid = (l + r) >> 1; 17 build(l, mid, lrt); 18 build(mid+1, r, rrt); 19 seg[rt].resize(r-l+1); 20 merge(seg[lrt].begin(), seg[lrt].end(), seg[rrt].begin(), seg[rrt].end(), seg[rt].begin()); 21 } 22 23 int query(int L, int R, int v, int l, int r, int rt) { 24 if(R < l || r < L) return 0; 25 if(L <= l && r <= R) return upper_bound(seg[rt].begin(), seg[rt].end(), v) - seg[rt].begin(); 26 int mid = (l + r) >> 1; 27 return query(L, R, v, l, mid, lrt) + query(L, R, v, mid+1, r, rrt); 28 } 29 30 inline bool scan_d(int &num) { 31 char in;bool IsN=false; 32 in=getchar(); 33 if(in==EOF) return false; 34 while(in!='-'&&(in<'0'||in>'9')) in=getchar(); 35 if(in=='-'){ IsN=true;num=0;} 36 else num=in-'0'; 37 while(in=getchar(),in>='0'&&in<='9'){ 38 num*=10,num+=in-'0'; 39 } 40 if(IsN) num=-num; 41 return true; 42 } 43 44 inline void out(int x) { 45 if (x > 9) out(x / 10); 46 putchar(x % 10 + '0'); 47 } 48 49 int main() { 50 // freopen("in", "r", stdin); 51 // freopen("out", "w", stdout); 52 int T, l, r, k, _ = 1; 53 scan_d(T); 54 while(T--) { 55 scan_d(n); scan_d(q); 56 for(int i = 1; i <= n; i++) scan_d(a[i]); 57 build(1, n, 1); 58 sort(a+1, a+n+1); 59 printf("Case %d: ", _++); 60 while(q--) { 61 scan_d(l); scan_d(r); scan_d(k); 62 l++; r++; 63 int lo = 1, hi = n; 64 int ret = query(l, r, k, 1, n, 1); 65 printf("%d ", ret); 66 } 67 } 68 return 0; 69 }
用数组写了个,快了不少。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define lrt rt << 1 5 #define rrt rt << 1 | 1 6 const int maxn = 100100; 7 int n, q, a[maxn]; 8 int ll[maxn], rr[maxn]; 9 int seg[20][maxn]; 10 11 void build(int l, int r, int rt) { 12 if(l == r) { 13 seg[rt][l] = a[l]; 14 return; 15 } 16 int mid = (l + r) >> 1; 17 build(l, mid, rt+1); 18 build(mid+1, r, rt+1); 19 // merge(seg[rt+1]+l, seg[rt+1]+mid+1, seg[rt+1]+mid+1, seg[rt+1]+r+1, seg[rt]+l); 20 int n1 = mid - l + 1, n2 = r - (mid + 1) + 1; 21 int i = 0, j = 0; 22 for(int ii = 0; ii < n1; ii++) ll[ii] = seg[rt+1][l+ii]; 23 for(int ii = 0; ii < n2; ii++) rr[ii] = seg[rt+1][(mid+1)+ii]; 24 while(i < n1 && j < n2) { 25 if(ll[i] <= rr[j]) seg[rt][l++] = ll[i++]; 26 else seg[rt][l++] = rr[j++]; 27 } 28 while(i < n1) seg[rt][l++] = ll[i++]; 29 while(j < n2) seg[rt][l++] = rr[j++]; 30 } 31 32 int query(int L, int R, int v, int l, int r, int rt) { 33 if(r < L || R < l) return 0; 34 if(L <= l && r <= R) return upper_bound(seg[rt]+l, seg[rt]+r+1, v) - (seg[rt]+l); 35 int mid = (l + r) >> 1; 36 return query(L, R, v, l, mid, rt+1) + query(L, R, v, mid+1, r, rt+1); 37 } 38 39 int main() { 40 // freopen("in", "r", stdin); 41 // freopen("out", "w", stdout); 42 int T, l, r, k, _ = 1; 43 scanf("%d", &T); 44 while(T--) { 45 scanf("%d%d",&n,&q); 46 for(int i = 1; i <= n; i++) scanf("%d", &a[i]); 47 build(1, n, 1); 48 printf("Case %d: ", _++); 49 while(q--) { 50 scanf("%d%d%d",&l,&r,&k); 51 l++; r++; 52 int lo = 1, hi = n; 53 int ret = query(l, r, k, 1, n, 1); 54 printf("%d ", ret); 55 } 56 } 57 return 0; 58 }