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
", 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:
", 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
", query(root[l-1], root[r], tmp, 1, cnt));
87         }
88     }
89     return 0;
90 }
原文地址:https://www.cnblogs.com/fightfordream/p/6031243.html