一 问题描述
A 国在海岸线沿直线部署了 N 个工兵营地,C 国通过先进的监测手段,对 A 国的每个工兵营里的人数都掌握的一清二楚,每个工兵营的人数都可能发生变动,可能增加或减少若干人数。
二 输入和输出
1 输入
第 1 行包含一个整数,T 表示有 T 组数据。每组数据的第 1 行都包含一个正整数,N 表示 N 个工兵营地。接下来的 N 个正数数,第 i 个正数数 ai 代表第 i 个工兵营地开始时有 ai 个人,在接下来的每行都有 1 条命令,每组数据最多有40000 条命令。命令有四种形式。
Add i j:第 i 个营地增加 j 个人
Sub i j:第 i 个营地减少 j 个人
Query i j:查询第 i ~ j 个营地的总人数
End:退出
2 输出
对第 i 组数据,首先单行输出 Case i,然后对每个 Query 都单行输出查询区间的总人数。
三 输入和输出样例
1 输入样例
1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End
2 输出样例
Case 1:
6
33
59
四 分析和设计
1 分析
本问题包含点更新和区间查询,可以采用树状数组或者线段树解决。
2 算法设计
a 创建线段树存储区间和。
b 点更新,查询到该点后进行点更新,返回时更新区间和。
c 区间查询,首先查找该区间,然后返回区间和值。
五 代码
package com.platform.modules.alg.alglib.hdu1166;
public class Hdu1166 {
public String output = "";
private final int maxn = 55555;
private int a[] = new int[maxn];
private int sum[] = new int[maxn << 2];
// 更新和值
void PushUP(int rt) {
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
// 构建线段树
void build(int l, int r, int rt) {
if (l == r) {
sum[rt] = a[l];
return;
}
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
PushUP(rt);
}
// 单点更新
void update(int p, int add, int l, int r, int rt) {
if (l == r) {
sum[rt] += add;
return;
}
int m = (l + r) >> 1;
if (p <= m) update(p, add, l, m, rt << 1);
else update(p, add, m + 1, r, rt << 1 | 1);
PushUP(rt);
}
// 区间查询
int query(int L, int R, int l, int r, int rt) {
if (L == l && r == R)//判断条件为相等
return sum[rt];
int m = (l + r) >> 1;
if (R <= m)
return query(L, R, l, m, rt << 1);
else if (L > m)
return query(L, R, m + 1, r, rt << 1 | 1);
else return query(L, m, l, m, rt << 1) + query(m + 1, R, m + 1, r, rt << 1 | 1);
}
public String cal(String input) {
int n;
String[] line = input.split("\n");
n = Integer.parseInt(line[0]); // 10
String[] nums = line[1].split(" ");
for (int x = 1; x <= n; x++)
a[x] = Integer.parseInt(nums[x - 1]);
build(1, n, 1);
int count = 2;
while (true) {
String[] command = line[count++].split(" ");
if (command[0].equals("End")) break;
int i = Integer.parseInt(command[1]);
int j = Integer.parseInt(command[2]);
if (command[0].equals("Query")) {
output += query(i, j, 1, n, 1) + "\n";
} else if (command[0].equals("Sub")) {
update(i, -j, 1, n, 1);
} else {
update(i, j, 1, n, 1);
}
}
return output;
}
}
六 测试

本文介绍了一种利用线段树解决区间查询与点更新问题的方法。通过实例详细展示了线段树构建、更新及查询的过程,并提供了完整的代码实现。

622

被折叠的 条评论
为什么被折叠?



