• segment树(线段树)


    线段树(segment tree)是一种Binary Search Tree或者叫做ordered binary tree。对于线段树中的每一个非叶子节点[a,b],它的左子树表示的区间为[a,(a+b)/2],右子树表示的区间为[(a+b)/2+1,b]。如下图:

                                                                     [0-2]

                                                                    /      

                                                             [0-1]          [2-2]

                                                             /    

                                                        [0-0]    [1-1]

    下面看一道leetcode上的题,求动态区间的和(Range Sum Query - Mutable),题目如下:

    Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.
    
    The update(i, val) function modifies nums by updating the element at index i to val.
    Example:
    Given nums = [1, 3, 5]
    
    sumRange(0, 2) -> 9
    update(1, 2)
    sumRange(0, 2) -> 8
    Note:
    The array is only modifiable by the update function.
    You may assume the number of calls to update and sumRange function is distributed evenly

    分析如下:

    一、构造线段树节点:

        class SegmentTreeNode {
            int start, end;
            int sum;
            SegmentTreeNode ltree, rtree;
            public SegmentTreeNode(int s, int e) {
                start = s;
                end = e;
            }
        }

    二、建立线段树(根据数组nums,建立一个动态区间求和的线段树):

        public SegmentTreeNode buildTree(int[] nums, int left, int right) {
            SegmentTreeNode root = new SegmentTreeNode(left, right);
            if (left == right) {
                root.sum = nums[left];
            } else {
                int mid = left + (right - left)/2;
                root.ltree = buildTree(nums, left, mid);
                root.rtree = buildTree(nums, mid+1, right);
                root.sum = root.ltree.sum + root.rtree.sum;
            }
            return root;
        }

    三、线段树的更新(更新int数组下标i的值为val):

        private void update(SegmentTreeNode root, int i, int val) {
            if (root.start == root.end) {
                root.sum = val;
            } else {
                int mid = root.start + (root.end-root.start)/2;
                if (i <= mid) {
                    update(root.ltree, i, val);
                } else {
                    update(root.rtree, i, val);
                }
                root.sum = root.ltree.sum + root.rtree.sum;
            }
        }

    四、线段树的查询(查询int数组下标 i 到 j 的元素之和):

        private int sumRange(SegmentTreeNode root, int i, int j) {
            if (root.start == i && root.end == j) {
                return root.sum;
            } else {
                int mid = root.start + (root.end - root.start)/2;
                if (j <= mid) {
                    return sumRange(root.ltree, i, j);
                } else if (i > mid) {
                    return sumRange(root.rtree, i, j);
                } else {
                    return sumRange(root.ltree, i, root.ltree.end) + sumRange(root.rtree, root.rtree.start, j);
                }
            }
        }

    综上所述,上面Range Sum Query - Mutable的AC代码如下:

    class SegmentTreeNode {
        int start, end;
        int sum;
        SegmentTreeNode ltree, rtree;
        public SegmentTreeNode(int s, int e) {
            start = s;
            end = e;
        }
    }
    
    public class NumArray {
        SegmentTreeNode root = null;
        
        public NumArray(int[] nums) {
            if(nums == null || nums.length == 0) {
                return;
            }
            root = buildTree(nums, 0, nums.length-1);
        }
    
        public SegmentTreeNode buildTree(int[] nums, int left, int right) {
            SegmentTreeNode root = new SegmentTreeNode(left, right);
            if (left == right) {
                root.sum = nums[left];
            } else {
                int mid = left + (right - left)/2;
                root.ltree = buildTree(nums, left, mid);
                root.rtree = buildTree(nums, mid+1, right);
                root.sum = root.ltree.sum + root.rtree.sum;
            }
            return root;
        }
        
        void update(int i, int val) {
            update(root, i, val);
        }
    
        private void update(SegmentTreeNode root, int i, int val) {
            if (root.start == root.end) {
                root.sum = val;
            } else {
                int mid = root.start + (root.end-root.start)/2;
                if (i <= mid) {
                    update(root.ltree, i, val);
                } else {
                    update(root.rtree, i, val);
                }
                root.sum = root.ltree.sum + root.rtree.sum;
            }
        }
    
        public int sumRange(int i, int j) {
             return sumRange(root, i, j);
        }
    
        private int sumRange(SegmentTreeNode root, int i, int j) {
            if (root.start == i && root.end == j) {
                return root.sum;
            } else {
                int mid = root.start + (root.end - root.start)/2;
                if (j <= mid) {
                    return sumRange(root.ltree, i, j);
                } else if (i > mid) {
                    return sumRange(root.rtree, i, j);
                } else {
                    return sumRange(root.ltree, i, root.ltree.end) + sumRange(root.rtree, root.rtree.start, j);
                }
            }
        }
    }
  • 相关阅读:
    VFL语言简洁
    TETeLasr Cutting System 开机回零问题
    TETELaser Cutting System 不连续吹起的问题
    C语言 printf 格式化输出函数
    kbhit()
    电子齿轮 电子凸轮
    memset
    .h(头文件) .lib(库文件) .dll(动态链接库文件) 之间的关系和作用的区分
    pdf点击超链接后返回:alt+ 向左 /向右
    关于 char 、 wchar_t 、 TCHAR 、 _T() ||| 宏 _T 、 TEXT 、 _TEXT 、 L
  • 原文地址:https://www.cnblogs.com/lasclocker/p/4979933.html
Copyright © 2020-2023  润新知