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);
            }
        }
    }
}
segment树(线段树)的更多相关文章
- 浅谈树套树(线段树套平衡树)&学习笔记
		
0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...
 - 【BZOJ-3165】Segment      李超线段树(标记永久化)
		
3165: [Heoi2013]Segment Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 368 Solved: 148[Submit][Sta ...
 - codeforces 242E - XOR on Segment (线段树  按位数建树)
		
E. XOR on Segment time limit per test 4 seconds memory limit per test 256 megabytes input standard i ...
 - HDU 4107 Gangster Segment Tree线段树
		
这道题也有点新意,就是须要记录最小值段和最大值段,然后成段更新这个段,而不用没点去更新,达到提快速度的目的. 本题过的人非常少,由于大部分都超时了,我严格依照线段树的方法去写.一開始竟然也超时. 然后 ...
 - Luogu P4097 [HEOI2013]Segment 李超线段树
		
题目链接 \(Click\) \(Here\) 李超线段树的模板.但是因为我实在太\(Naive\)了,想象不到实现方法. 看代码就能懂的东西,放在这里用于复习. #include <bits/ ...
 - 2019.02.11 bzoj3165: [Heoi2013]Segment(线段树)
		
传送门 题意简述:要求支持两种操作: 插入一条线段. 询问与直线x=kx=kx=k相交的线段中,交点最靠上的线段的编号. 思路: 直接上李超线段树即可. 代码: #include<bits/st ...
 - Segment 李超线段树
		
题目大意: 要求在平面直角坐标系下维护两个操作: 1.在平面上加入一条线段.记第 i 条被插入的线段的标号为 i 2.给定一个数 k,询问与直线 x = k 相交的线段中,交点最靠上的线段的编号. 若 ...
 - 【洛谷P4097】Segment 李超线段树
		
题目大意:维护一个二维平面,给定若干条线段,支持询问任意整数横坐标处对应的纵坐标最靠上的线段的 id,相同高度取 id 值较小的,强制在线. 题解:初步学习了李超线段树.李超线段树的核心思想在于通过标 ...
 - BZOJ3165: [Heoi2013]Segment(李超线段树)
		
题意 题目链接 Sol 李超线段树板子题.具体原理就不讲了. 一开始自己yy着写差点写自闭都快把叉积搬出来了... 后来看了下litble的写法才发现原来可以写的这么清晰简洁Orz #include& ...
 
随机推荐
- GitHub_Hexo_Next 搭建博客
			
利用最新版本的 hexo+next 重构了个人博客,下面简单记录了搭建博客的完整过程: 一.环境准备 1.安装 Node.js 2.安装 Git 3.注册 Github 账号 二.在GitHub上创建 ...
 - Xshell和Xftp 安装及使用
			
Xshell Xshell 是一个强大的安全终端模拟软件,它支持SSH1, SSH2, 以及Microsoft Windows 平台的TELNET 协议.Xshell 通过互联网到远程主机的安全连接以 ...
 - html5 svg实现不规则形状图片触发事件
			
html5 svg实现不规则形状图片触发事件<pre><!DOCTYPE html><html lang="en"> <head> ...
 - Geotools求shapefile路网中任意两点之间最短路径的距离
			
前言:之前在博问求助过这个问题.经过几天的思考,算是解决了(但仍有不足),另一方面对Geotools不是很熟,有些描述可能不正确,希望大家批评指正. 问题:作为一个新手,我并没有发现Geotools中 ...
 - 4、Vim编辑器与正则表达式-面试题
			
题目 自己写答案
 - JavaScript 运行原理
			
i{margin-right:4px;margin-top:-0.2em}.like_comment_tips .weui-icon-success{background:transparent ur ...
 - visible:hidden和dispaly:none的区别
			
display:none和visible:hidden都能把网页上某个元素隐藏起来,但两者有区别: display:none ---不为被隐藏的对象保留其物理空间,即该对象在页面上彻底消失,通俗来说就 ...
 - Mybatis精讲(二)---生命周期
			
目录 回顾 SqlSessionFactoryBuilder SqlSessionFactory openSessionFromDataSource Executor SqlSession Mappe ...
 - 领扣(LeetCode)最长和谐子序列 个人题解
			
和谐数组是指一个数组里元素的最大值和最小值之间的差别正好是1. 现在,给定一个整数数组,你需要在所有可能的子序列中找到最长的和谐子序列的长度. 示例 1: 输入: [1,3,2,2,5,2,3,7] ...
 - 领扣(LeetCode)3的幂 个人题解
			
给定一个整数,写一个函数来判断它是否是 3 的幂次方. 示例 1: 输入: 27 输出: true 示例 2: 输入: 0 输出: false 示例 3: 输入: 9 输出: true 示例 4: 输 ...