HDU 4417 , 山东省赛Boring counting 主席树

题目链接

题意

求的是某一段区间内小于等于K的数字的个数。

思路

我们可以一开始输入的时候就把a[]和要询问的K存到一个b[]里,再求出a[]在b[]中的位置,建立n棵线段树,最后要求小于等于K的个数,实际上就是求第R棵线段树- 第L - 1棵线段树的那个线段树中区间端点的范围在1-K的总和。觉得这种方法很妙,大部分的题解都是用了二分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <set>
#include <queue>

using namespace std;
const int maxn = 100005;
struct node{
int ls, rs, sum;
}tree[2500050];

int tot, a[maxn], b[2 * maxn], rt[maxn] , h[maxn],l[maxn],r[maxn];
void build(int &o , int l, int r)
{
o = ++tot;
tree[o].sum = 0;
if(l == r) return;
int mid = (l + r) >> 1;
build(tree[o].ls, l ,mid);
build(tree[o].rs, mid + 1, r);
}

void update(int &o, int last, int l, int r, int pos)
{
o = ++tot;
tree[o].ls = tree[last].ls;
tree[o].rs = tree[last].rs;
tree[o].sum = tree[last].sum + 1;
if(l == r) return;
int mid = (l + r) >> 1;
if(pos <= mid) update(tree[o].ls, tree[last].ls, l, mid, pos);
else update(tree[o].rs, tree[last].rs, mid + 1, r, pos);
}

int Sum;
void query(int o, int last, int l ,int r, int left, int right)
{
if(left > r || right < l) return;
if(left <= l && r <= right)
{
Sum += tree[o].sum - tree[last].sum;
return;
}
int mid = (l + r) >> 1;
query(tree[o].ls, tree[last].ls, l, mid, left, right);
query(tree[o].rs, tree[last].rs, mid + 1, r, left, right);
}
int main()
{
int T,caser = 1;
scanf("%d",&T);
while(T--)
{
tot = 0;
memset(tree, 0, sizeof(tree));
int n,Q;
scanf("%d %d",&n,&Q);
for(int i = 1; i <= n; ++i)
{
scanf("%d",&a[i]);
b[i] = a[i];
}
for(int i = 1; i <= Q; ++i)
{
scanf("%d %d %d",&l[i],&r[i],&h[i]);
b[n + i] = h[i];
}
sort(b + 1, b + n + Q + 1);
int N = unique(b + 1, b + n + Q + 1) - (b + 1);
build(rt[0], 1, N);
for(int i = 1; i <= n; ++i)
{
a[i] = lower_bound(b + 1, b + N + 1, a[i]) - b;
}
for(int i = 1; i <= n; ++i)
{
update(rt[i], rt[i - 1], 1, N, a[i]);
}
cout << "Case " << caser++ << ":" << '\n';
for(int i = 1; i <= Q; ++i)
{
Sum = 0;
int v = lower_bound(b + 1, b + N + 1, h[i]) - b;
query(rt[r[i] + 1], rt[l[i]], 1, N, 1, v);
printf("%d\n",Sum);
}
}
}

山东省第四届省赛

Boring counting

和上面的几乎一样了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <set>
#include <queue>

using namespace std;
const int maxn = 50005;
struct node{
int ls, rs, sum;
}tree[maxn * 20];
int a[maxn], b[3 * maxn], rt[maxn],l[maxn], r[maxn] , k1[maxn], k2[maxn];
int tot, Sum;
void build(int &o, int l, int r)
{
o = ++tot;
tree[o].sum = 0;
if(l == r) return;
int mid = (l + r) >> 1;
build(tree[o].ls, l , mid);
build(tree[o].rs, mid + 1, r);
}

void update(int &o, int last, int l, int r, int pos)
{
o = ++tot;
tree[o].ls = tree[last].ls;
tree[o].rs = tree[last].rs;
tree[o].sum = tree[last].sum + 1;
if(l == r) return;
int mid = (l + r) >> 1;
if(pos <= mid) update(tree[o].ls, tree[last].ls, l, mid, pos);
else update(tree[o].rs, tree[last].rs, mid + 1, r, pos);
}

void query(int o, int last, int l, int r, int left, int right)
{
if(left > r || right < l) return;
if(left <= l && right >= r)
{
Sum += tree[o].sum - tree[last].sum;
return;
}
int mid = (l + r) >> 1;
query(tree[o].ls, tree[last].ls, l, mid, left, right);
query(tree[o].rs, tree[last].rs, mid + 1, r, left, right);
}

int main()
{
int T,n,Q, caser = 1;
scanf("%d",&T);
while(T--)
{
tot = 0;
scanf("%d %d",&n,&Q);
for(int i = 1; i <= n; ++i)
{
scanf("%d",&a[i]);
b[i] = a[i];
}
int tot1 = n;
for(int i = 1; i <= Q; ++i)
{
scanf("%d %d %d %d",&l[i],&r[i],&k1[i],&k2[i]);
b[++tot1] = k1[i] - 1;
b[++tot1] = k2[i];
}
sort(b + 1, b + tot1 + 1);
int N = unique(b + 1, b + tot1 + 1) - (b + 1);
build(rt[0], 1, N);
for(int i = 1; i <= n; ++i)
{
a[i] = lower_bound(b + 1, b + N + 1, a[i]) - b;
update(rt[i], rt[i - 1], 1, N, a[i]);
}
printf("Case #%d:\n",caser++);
for(int i = 1; i <= Q; ++i)
{
Sum = 0;
int v = lower_bound(b + 1, b + N + 1,k1[i] - 1) - b;
query(rt[r[i]], rt[l[i] - 1], 1, N, 1, v);
int num1 = Sum;
v = lower_bound(b + 1, b + N + 1, k2[i]) - b;
Sum = 0;
query(rt[r[i]], rt[l[i] - 1], 1, N, 1, v);
printf("%d\n", Sum - num1);

}
}
}