HDU1166 敌兵布阵

题面:http://acm.hdu.edu.cn/showproblem.php?pid=1166

HDU1166-敌兵布阵

题意

单点修改区间和查询。
线段树&树状数组&分块等等等等模板题。

解法

给出数状数组和分块的解法。
数状数组不多讲了。就套个模板。

BIT例程

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
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;

int bit[maxn], n;
inline int lowbit(int i)
{
return i & (-i);
}
int sum(int i)
{
int res = 0;
while(i > 0)
{
res += bit[i];
i -= lowbit(i);
}
return res;
}
void add(int i, int x)
{
while(i <= n)
{
bit[i] += x;
i += lowbit(i);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
for(int cas = 1; cas <= T; cas++)
{
memset(bit, 0, sizeof(bit));
cin >> n;
for(int i = 1; i <= n; i++)
{
int t;
cin >> t;
add(i, t);
}
string q;
int i, j;
cout << "Case " << cas << ":\n";
while(cin >> q)
{
if(q[0] == 'E')
break;
cin >> i >> j;
if(q[0] == 'A')
add(i, j);
else if(q[0] == 'Q')
cout << sum(j) - sum(i - 1) << endl;
else
add(i, -j);
}
}
}

简单说明下分块,分块就是将整段的区间分成若干块,对区间进行一系列的操作。
最后要进行查询的时候整块的区间就查询整块,剩下的部分的就暴力操作。
常规处理分成$sqrt(n)$块,可以达到$O(sqrt(n))$的时间复杂度
对于本题而言,首先将区间分块,区间内的和单独记录,最后求和的时候整块的区间直接加和,区间外的单独加即可。

分块例程

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
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;

int a[maxn], b[maxn];
int n, block, num;
int belong[maxn], l[maxn], r[maxn];
int sum(int L, int R)
{
int res = 0;
for(int i = L; i <= min(R, r[belong[L]]); i++)
res += a[i];
if(R <= r[belong[L]])
return res;
for(int i = belong[L] + 1; i < belong[R]; i++)
res += b[i];
for(int i = l[belong[R]]; i <= R; i++)
res += a[i];
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
for(int cas = 1; cas <= T; cas++)
{
cin >> n;
memset(b, 0, sizeof(b));
block = sqrt(n);
num = n / block;
if(n % block)num++;
for(int i = 1; i <= n; i++)
belong[i] = (i - 1) / block + 1;
for(int i = 1; i <= num; i++)
{
l[i] = 1 + (i - 1) * block;
r[i] = block * i;
}
r[num] = n;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
b[belong[i]] += a[i];
}
string q;
int i, j;
cout << "Case " << cas << ":\n";
while(cin >> q)
{
if(q[0] == 'E')
break;
cin >> i >> j;
if(q[0] == 'A')
{
b[belong[i]] += j;
a[i] += j;
}
else if(q[0] == 'Q')
cout << sum(i, j) << endl;
else
{
b[belong[i]] -= j;
a[i] -= j;
}
}
}
}

线段树

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
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int a[maxn], b[maxn];
int dat[2 * maxn - 1];
int n;
void init(int _n)
{
n = 1;
while(n < _n)
n *= 2;
for(int i = 0; i < 2 * n - 1; i++)
dat[i] = 0;
}
void update(int k, int a)
{
k += n - 1;
dat[k] = a;
while(k > 0)
{
k = (k - 1) / 2;
dat[k] = dat[k * 2 + 1] + dat[k * 2 + 2];
}
}
int query(int a, int b, int k, int l, int r)
{
if(r <= a || b <= l)
return 0;
if(a <= l && b >= r)
return dat[k];
int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
return vl + vr;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
for(int cas = 1; cas <= T; cas++)
{
int q; cin >> q;
init(q);
for(int i = 0; i < q; i++)
{
int t; cin >> t;
update(i, t);
}
string s;
cout << "Case " << cas << ":\n";
while(cin >> s)
{
if(s[0] == 'E')
break;
if(s[0] == 'Q')
{
int l, r; cin >> l >> r;
cout << query(l - 1, r, 0, 0, n) << endl;
}
else if(s[0] == 'A')
{
int l, r; cin >> l >> r;
int val = query(l - 1, l , 0, 0, n);
update(l - 1, val + r);
}
else
{
int l, r; cin >> l >> r;
int val = query(l - 1, l , 0, 0, n);
update(l - 1, val - r);
}
}
}
return 0;

}