线段树(Java)

一、线段树基本原理

1.懒数组
2.懒更新

二、线段树代码实现

package Tree;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;

import javax.management.Query;
import javax.swing.plaf.basic.BasicInternalFrameTitlePane.IconifyAction;

public class RangeTree {
	
	private int[] num;	// 初始数组
	private int[] sum;	// 总和 树结构
	private int[] lazy;	// 懒数组
	private boolean[] update;	// 懒更新
	private int[] change; // 懒更新的值
	
	/**
	 * 
	 * @param original 原始数组
	 */
	public RangeTree(int[] original) {
		int N = original.length;
		num = new int[N+1];
		for(int i=0; i<N; ++i) {
			num[i+1] = original[i];
		}
		
		sum = new int[N << 2];
		lazy = new int[N << 2];
		update = new boolean[N << 2];
		change = new int[N << 2];
		build(1, N, 1, N, 1);
	}
	
	/**
	 * 
	 * @param L	要处理的范围 左边界
	 * @param R	要处理的范围 右边界
	 * @param l	当前节点代表的左边界
	 * @param r	当前节点代表的右边界
	 * @param index	当前处理节点
	 */
	private void build(int L, int R, int l, int r, int index) {
		if(l == r) {
			sum[index] = num[l];
			return;
		}
		int mid = l + ((r - l) >> 1);	// 节点范围划分的位置
		if (L <= mid) {	//左子树
			build(L, R, l, mid, index << 1);
		}
		if(R > mid) {
			build(L, R, mid+1, r, (index << 1) | 1 );//右子树
		}
		pushUp(index);// 更新
	}
	
	private void pushUp(int index) {
		sum[index] = sum[index << 1] + sum[(index << 1) | 1];
	}
	
	
	public void add(int L, int R, int add_num) {
		add(L, R, 1, num.length-1, 1, add_num);
	}
	
	private void add(int L, int R, int l, int r, int index, int add_num) {
		if(L<=l && R >=r) {
			lazy[index] += add_num;
			sum[index] += (r - l + 1) * add_num;
			return;
		}
		int mid = l + ((r - l) >> 1);
		pushDown(index, mid - l + 1, r - mid);
		if(L <= mid) {
			add(L, R, l, mid, index << 1, add_num);
		}
		if(R > mid) {
			add(L, R, mid + 1, r, index << 1 | 1, add_num);
		}
		pushUp(index);
	}
	
	/**
	 * 将当前节点index的懒更新与懒加数下放
	 * @param index
	 * @param ln
	 * @param rn
	 */
	private void pushDown(int index, int ln, int rn) {
		if(update[index]) {
			update[index << 1] = true;
			change[index << 1] = change[index];
			sum[index << 1] = change[index] * ln;
			lazy[index << 1] = 0;
			
			update[index << 1 | 1] = true;
			change[index << 1 | 1] = change[index];
			sum[index << 1 | 1] = change[index] * rn;
			lazy[index << 1 | 1] = 0;
			
			update[index] = false;
		}
		if(lazy[index] != 0) {
			lazy[index << 1] += lazy[index];
			lazy[(index << 1) | 1] += lazy[index];
			
			sum[index << 1] += lazy[index] * ln;
			sum[(index << 1) | 1] += lazy[index] * rn;
			
			lazy[index] = 0;
		}
	}
	
	public void update(int L, int R, int val) {
		update(L, R, val, 1, num.length-1, 1);
	}
	
	public void update(int L, int R, int val, int l, int r, int index) {
		if(L <= l && r <= R) {
			update[index] = true;
			change[index] = val;
			sum[index] = val * (r - l + 1);
			return ;
		}
		int mid = l + ((r - l) >> 1);
		pushDown(index, mid - l + 1, r - mid);
		if(L <= mid) {
			update(L, R, val, l, mid, index << 1);
		}
		if(R > mid) {
			update(L, R, val, mid+1, r, index << 1 | 1);
		}
		pushUp(index);
	}
	
	public String query(int R, int L) {
		return "query["+R+","+L+"]:"+query(R, L, 1, num.length-1, 1);
	}
	
	private int query(int L, int R, int l, int r, int index) {
		if(L <= l && r <= R) {
			return sum[index];
		}
		int mid = l + ((r - l) >> 1);
		pushDown(index, mid - l + 1, r - mid);
		int ret = 0;
		if(L <= mid) {
			ret += query(L, R, l, mid, index << 1);
		}
		if(R > mid) {
			ret += query(L, R, mid + 1, r, index << 1 | 1);
		}
		return ret;
	}
	
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		StringBuilder sBuilder = new StringBuilder();
		toStringHelper(1, num.length - 1, sBuilder, 1);
		return "树中各节点的状态为\n"+sBuilder.toString();
	}
	
	public void toStringHelper(int l, int r, StringBuilder sb, int index) {
		Queue<int[]> queue = new LinkedList<int[]>();
		queue.add(new int[] {index, l, r});
		while(!queue.isEmpty()) {
			int size = queue.size();
			for(int i=0; i<size; ++i) {
				int[] now = queue.poll();
				sb.append("["+ now[1] + "," + now[2]+"]{sum:"+sum[now[0]]);
				if(lazy[now[0]] != 0) {
					sb.append(", lazy:"+lazy[now[0]]);
				}
				if(update[now[0]]) {
					sb.append(", change:"+change[now[0]]);
				}
				sb.append("}\t");
				if(now[1] != now[2]) {
					int mid = now[1] + ((now[2] - now[1]) >> 1);
					queue.add(new int[] {now[0] << 1, now[1], mid});
					queue.add(new int[] {now[0] << 1 | 1, mid+1, now[2]});
				}
				
			}
			sb.append("\n");
		}
	}
	
	
	public static void main(String[] args) {
		RangeTree rTree = new RangeTree(new int[] {1, 1, 1, 1, 1, 1});
		System.out.println("--------原始树---------");
		System.out.println(rTree);	// 1, 1, 1, 1, 1, 1
		System.out.println("----【1,5】范围加1后查询【3,6】范围的和---------");
		rTree.add(1, 5, 1);	// 2, 2, 2, 2, 2, 1
		System.out.println(rTree);
		System.out.println(rTree.query(3,6));
		System.out.println("----【1,4】范围变成4后查询【3,6】【1,6】范围的和---------");
		rTree.update(1, 4, 4);		// 4, 4, 4, 4, 2, 1
		System.out.println(rTree);
		System.out.println(rTree.query(1, 6));
		System.out.println(rTree.query(3, 6));
	}
	
}

执行结果:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值