线段树

此处线段树是求区间和的用例

基本操作其实只有三个:

  1. 建立线段树,如果不是叶子结点,就递归向下构造,这里用data中的数据作为叶子结点的weight来构造。
  2. 更新线段树,更新data某个位置的值,需要将所有包含该位置的线段树更新。注意data和线段树是分开的,调用update方法并不影响data数组的值。
  3. 查询某一区间的值,使用线段树查询。
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;
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值