[HDOJ4417]Super Mario(归并树)

题目链接: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 }
原文地址:https://www.cnblogs.com/kirai/p/6927649.html