HDU 4417:Super Mario(主席树)
http://acm.hdu.edu.cn/showproblem.php?pid=4417
题意是:给出n个数和q个询问,每个询问有一个l,r,h,问在[l,r]这个区间里面有多少个数是小于等于h的。
思路:比较裸的主席树,注意题意给的区间是从[0,n-1],一开始看错导致想错了很多东西。询问的时候如果m < h,那么左子树全部都是小于 h 的,就加上左子树的 sum,继续查右子树,否则就查左子树。最后 l == r 的时候要判下 h >= l,因为这个也错了几次。从师兄那里学习到了如果找一个数,如果找不到就返回一个比它小的数,那么可以用 upper_bound() 找到的下标 -1。就不用 lower_bound() 找到后判断等不等于,不等于的话下标 -1 这么麻烦了。(upper_bound()返回的是大于查的数的下标,所以 -1就可以等于或者小于了。)
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <algorithm> 5 using namespace std; 6 #define N 100010 7 struct node 8 { 9 int l, r, sum; 10 }tree[N*40]; 11 int root[N], tot, a[N], b[N], cnt; 12 13 void update(int pre, int &now, int id, int l, int r) 14 { 15 now = ++tot; tree[now] = tree[pre]; 16 tree[now].sum++; 17 if(l == r) return ; 18 int m = (l + r) >> 1; 19 if(id <= m) update(tree[pre].l, tree[now].l, id, l, m); 20 else update(tree[pre].r, tree[now].r, id, m + 1, r); 21 } 22 23 int query(int L, int R, int h, int l, int r) 24 { 25 int ans = 0; 26 int m = (l + r) >> 1; 27 if(l == r) { 28 if(h >= l) ans += tree[R].sum - tree[L].sum; // 注意要判下这个 29 /* 30 如果区间查询和更新的区间是(0, cnt)的话,那么就可以不用判定这个 31 因为如果查的区间是(3, 5, 5) 查 2 的话,那么会查到下标 0, 32 l > h,这个时候就错了 33 */ 34 return ans; 35 } 36 if(m < h) { 37 ans += tree[tree[R].l].sum - tree[tree[L].l].sum; // 如果 h > m 的话,左子树全部都小于h,全部都加上 38 ans += query(tree[L].r, tree[R].r, h, m + 1, r); 39 } else { 40 ans += query(tree[L].l, tree[R].l, h, l, m); 41 } 42 return ans; 43 } 44 45 void debug(int rt, int l, int r) 46 { 47 if(l == r) { 48 printf("%d : %d\n", l, tree[rt].sum); 49 return ; 50 } 51 int m = (l + r) >> 1; 52 debug(tree[rt].l, l, m); 53 debug(tree[rt].r, m+1, r); 54 } 55 56 int main() 57 { 58 int t, cas = 1; 59 scanf("%d", &t); 60 while(t--) { 61 int n, q; 62 scanf("%d%d", &n, &q); 63 64 tot = 0; 65 66 for(int i = 1; i <= n; i++) { 67 scanf("%d", &a[i]); 68 b[i] = a[i]; 69 } 70 sort(b + 1, b + 1 + n); 71 cnt = unique(b + 1, b + 1 + n) - b - 1; 72 for(int i = 1; i <= n; i++) { 73 a[i] = lower_bound(b + 1, b + 1 + cnt, a[i]) - b; 74 update(root[i-1], root[i], a[i], 1, cnt); 75 } 76 debug(root[n], 1, cnt); 77 printf("Case %d:\n", cas++); 78 for(int i = 1; i <= q; i++) { 79 int l, r, c; 80 scanf("%d%d%d", &l, &r, &c); 81 l++, r++; 82 int tmp = upper_bound(b + 1, b + 1 + cnt, c) - b - 1; 83 // int tmp = lower_bound(b + 1, b + 1 + cnt, c) - b; 84 // if(b[tmp] != c) tmp--; 85 // int tmp = lb(c); 86 printf("%d\n", query(root[l-1], root[r], tmp, 1, cnt)); 87 } 88 } 89 return 0; 90 }