此处线段树是求区间和的用例
基本操作其实只有三个:
- 建立线段树,如果不是叶子结点,就递归向下构造,这里用data中的数据作为叶子结点的weight来构造。
- 更新线段树,更新data某个位置的值,需要将所有包含该位置的线段树更新。注意data和线段树是分开的,调用update方法并不影响data数组的值。
- 查询某一区间的值,使用线段树查询。
import java.util.*;
public class Main {
static int[] data;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入您的数据规模");
int n = sc.nextInt();
data = new int[n];
for (int i = 0; i < n; i++) {
data[i] = sc.nextInt();
}
SegTree tree = SegTree.buildSegTree(0, n - 1);
System.out.println(tree.query(0, 3));
tree.update(0, 2);
System.out.println(tree.query(0, 3));
sc.close();
}
static class SegTree {
int l, r; // 左右子树的根结点下标
int weight; // 该树的权重
SegTree lSon; // 左孩子
SegTree rSon; // 右孩子
public SegTree(int l, int r) {
this.l = l;
this.r = r;
}
// 构造区间树
static SegTree buildSegTree(int l, int r) {
SegTree root = new SegTree(l, r);
// 如果为叶子结点,递归出口
if (l == r) {
root.weight = data[l];
return root;
}
// 不是叶子结点,递归构造子树
int mid = (l + r) / 2;
root.lSon = buildSegTree(l, mid);
root.rSon = buildSegTree(mid + 1, r);
root.weight = root.lSon.weight + root.rSon.weight;
return root;
}
// 更新区间树,num为在position位置要加或减的值
void update(int position, int num) {
// 是叶子结点,递归出口
if (l == r) {
weight += num;
return;
}
// 不是叶子结点
// 处理当前树
weight += num;
// 处理子树
int mid = (l + r) / 2;
if (position <= mid) {
lSon.update(position, num);
} else {
rSon.update(position, num);
}
}
// 查询[p1,p2]的和
int query(int p1, int p2) {
// 递归出口
if (p1 <= l && p2 >= r) {
return weight;
}
if (p1 > p2) {
return 0;
}
// 查询左右子树
int mid = (l + r) / 2;
int res = 0;
if (p1 <= mid) {
res += lSon.query(p1, p2);
}
if (p2 > mid) {
res += rSon.query(p1, p2);
}
return res;
}
}
}