一、线段树基本原理
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));
}
}
执行结果: