算法总结:线段树扫描线

一。线段树(segment tree)
线段树(segment tree)是用来存放给定区间(segment, or interval)内对应信息的一种数据结构。
线段树是一颗近似的完全二叉树,每个节点代表一个区间,节点的权值是该区间的最小值。根节点是整个区间。
每个节点的左孩子是该节点所代表的的区间的左半部分,右孩子是右半部分。
为方便起见,如果区间长度为奇数,则左孩子为较长的半部分。
通过线段树,我们可以用O(logn)的时间复杂度完成查询和更新操作。

1.1最小值/max 线段树

0,1,2,3,4,5,6,7 index
1,5,3,7,3,2,5,7 array

在这里插入图片描述

0,1,2,3,4,5,6,7 index
1,5,3,7,3,2,5,7 array

在这里插入图片描述

    private void buildTree(int[] nums) {
   
        for (int i = n, j = 0;  i < 2 * n; i++,  j++)
            tree[i] = nums[j];
        for (int i = n - 1; i > 0; --i)
            tree[i] = Math.min(tree[i * 2], tree[i * 2 + 1]); //min segment tree
            // tree[i] = tree[i * 2] + tree[i * 2 + 1]; //sum range segment tree
    }

segmentTree[1] = arr[0:8)
segmentTree[2] = arr[0:4)
segmentTree[3] = arr[4:8)
segmentTree[4] = arr[0:2)
segmentTree[5] = arr[2:4)
segmentTree[6] = arr[4:6)
segmentTree[7] = arr[6:8)
segmentTree[8] = arr[0]
segmentTree[9] = arr[1]
segmentTree[10] = arr[2]
segmentTree[11] = arr[3]
segmentTree[12] = arr[4]
segmentTree[13] = arr[5]
segmentTree[14] = arr[6]
segmentTree[15] = arr[7]

序列{5,9,7,4,6,1},length=6, mid=(left+right)/2
这棵树分左右两边,[0,2], [3,5]
[0,2]继续分,[0,1], [2,2]
[0,1]继续分,[0,0], [1,1]… …
在这里插入图片描述

1.2 区间和线段树 sum range
有一个数组[1, 3, 5, 7, 9, 11],线段树长这个样子:在这里插入图片描述

reference:黄浩杰讲解线段树(segment tree)
reference:Segment tree in Java

import java.util.Arrays;

public class SegmentTree {
   
    int[] tree;
    SegmentTree(int n){
   
        tree = new int[n];
    }

    public void build(int[] arr,int nodeIdx,int start,int end){
   
        if(start==end){
   
            tree[nodeIdx]=arr[start];
        }else{
   
            int mid=(start+end)/2;
            build(arr,2*nodeIdx+1,start,mid);//left tree_nodeIdx
            build(arr,2*nodeIdx+2,mid+1,end);//right tree_nodeIdx
            tree[nodeIdx]=tree[2*nodeIdx+1]+tree[2*nodeIdx+2];
        }
    }
    //index,value
    public void update(int[] arr,int nodeIdx,int index,int value,int start,int end){
   
        //find it
        if(start==end){
   
            arr[index]=value;
            tree[nodeIdx]=value;//?+=
        }else{
   
            int mid=(start+end)/2;
            if(start<=index && index<=mid){
    //in left tree
                update(arr,2*nodeIdx+1,index,value,start,mid);
            }else{
   
                update(arr,2*nodeIdx+2,index,value,mid+1,end);
            }
            tree[nodeIdx] = tree[2*nodeIdx+1] + tree[2*nodeIdx+2];
        }
    }
    // 0 1 2 3 4 5
    //{1,3,5,7,9,11};
    //query sum in range [2--5]
    public int query(int nodeIdx,int start,int end,int left,int right){
   
        //out of the arr bounds:
        if(right < start || left > end){
   
           return 0;
        }
        if(left <= start && end <= right){
    //all in left tree bounds ||all in right tree bounds
            return tree[nodeIdx];
        }
        //both in left & right tree
        int mid = (start + end)/2;
        int p1 = query(2*nodeIdx+1, start, mid, left, right);
        int p2 = query(2*nodeIdx+2, mid+1, end, left, right);
        return p1 + p2;
    }
    public static void main(String[] args) {
   
        int [] arr={
   1,3,5,7,9,11};
        int n=arr.length;
        int height=(int) (Math.log(n)/Math.log(2))+ 1;
        int tree_nodes = (int) Math.pow(2, height+1);
        SegmentTree s=new SegmentTree(tree_nodes);
        s.build(arr,0,0,5);
        for(int i = 0; i < tree_nodes; i++){
   
            System.out.print(s.tree[i] + " ");
        }
        System.out.println("\n"+"arr: "+ Arrays.toString(arr));
        System.out.println("\n"+"Query result: "+s.query(0, 0, n-1, 0,2));
        s.update(arr,0,1,2,0,n-1);
        for(int i = 0; i < tree_nodes; i++){
   
            System.out.print(s.tree[i] + " ");
        }
        System.out.println("\n"+"arr: "+ Arrays.toString(arr));
        System.out.println("\n"+"Query result: "+s.query(0, 0, n-1, 0,2));
    }
}

leetcode.307

class NumArray {
   
    int[] tree;
    int n;
    public NumArray(int[] nums) {
   
        if (nums.length > 0) {
   
            n = nums.length;
            tree = new int[n * 2];
            buildTree(nums);
        }
    }
    
    private void buildTree(int[] nums) {
   
        for (int i = n, j = 0;  i < 2 * n; i++,  j++)
            tree[i] = nums[j];
        for (int i = n - 1; i > 0; --i)
            tree[i] = tree[i * 2] + tree[i * 2 + 1];
    }
    
    void update(int pos, int val) {
   
        pos += n;//pos=2, pos=10
        tree[pos] = val;
        while (pos > 0) {
   
            int left = pos;
            int right = pos;
            if (pos % 2 == 0) {
   
                right = pos + 1;
            } else {
   
                left = pos - 1;
            }
            // parent is updated after child is updated
            //tree[10/2]  /tree[5/2]  /tree[2/2] 
            tree[pos / 2] = tree[left] + tree[right];
            pos /= 2;
        }
    }
    
    public int sumRange(int l, int r) {
   
        // get leaf with value 'l'
        l += n;
        // get leaf with value 'r'
        r += n;
        int sum = 0;
        while (l <= r) {
   
            if ((l % 2) == 1) {
   </
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值