线段树(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树(线段树)的更多相关文章

  1. 浅谈树套树(线段树套平衡树)&学习笔记

    0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...

  2. 【BZOJ-3165】Segment 李超线段树(标记永久化)

    3165: [Heoi2013]Segment Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 368  Solved: 148[Submit][Sta ...

  3. codeforces 242E - XOR on Segment (线段树 按位数建树)

    E. XOR on Segment time limit per test 4 seconds memory limit per test 256 megabytes input standard i ...

  4. HDU 4107 Gangster Segment Tree线段树

    这道题也有点新意,就是须要记录最小值段和最大值段,然后成段更新这个段,而不用没点去更新,达到提快速度的目的. 本题过的人非常少,由于大部分都超时了,我严格依照线段树的方法去写.一開始竟然也超时. 然后 ...

  5. Luogu P4097 [HEOI2013]Segment 李超线段树

    题目链接 \(Click\) \(Here\) 李超线段树的模板.但是因为我实在太\(Naive\)了,想象不到实现方法. 看代码就能懂的东西,放在这里用于复习. #include <bits/ ...

  6. 2019.02.11 bzoj3165: [Heoi2013]Segment(线段树)

    传送门 题意简述:要求支持两种操作: 插入一条线段. 询问与直线x=kx=kx=k相交的线段中,交点最靠上的线段的编号. 思路: 直接上李超线段树即可. 代码: #include<bits/st ...

  7. Segment 李超线段树

    题目大意: 要求在平面直角坐标系下维护两个操作: 1.在平面上加入一条线段.记第 i 条被插入的线段的标号为 i 2.给定一个数 k,询问与直线 x = k 相交的线段中,交点最靠上的线段的编号. 若 ...

  8. 【洛谷P4097】Segment 李超线段树

    题目大意:维护一个二维平面,给定若干条线段,支持询问任意整数横坐标处对应的纵坐标最靠上的线段的 id,相同高度取 id 值较小的,强制在线. 题解:初步学习了李超线段树.李超线段树的核心思想在于通过标 ...

  9. BZOJ3165: [Heoi2013]Segment(李超线段树)

    题意 题目链接 Sol 李超线段树板子题.具体原理就不讲了. 一开始自己yy着写差点写自闭都快把叉积搬出来了... 后来看了下litble的写法才发现原来可以写的这么清晰简洁Orz #include& ...

随机推荐

  1. day 1 堆 hash 线段树 树状数组 冰茶姬 字典树 二叉查找树

    来郑州的第二天,早上开始也没说什么就说了些注意安全,各种各样的注意安全... 冰茶姬: 原来再打食物链时看了一下冰茶姬,只注意了路径压缩,没想到还有什么按秩排序但确实快了不少... int find( ...

  2. Linux修改主机名!(图文)

    本篇作为之前的补充篇,如果想修改自己的主机名,方便老师检查作业是否是自己做的,可以用修改主机名的方法,那么怎么修改呢? 一. 使用hostname命令 比如我现在的主机名是haozhikuan-hbz ...

  3. 开源跳板机(堡垒机)系统 Jumpserver安装教程(带图文)

    环境 系统: CentOS 7 IP: 192.168.244.144 关闭 selinux 和防火墙 # CentOS 7 $ setenforce 0 # 可以设置配置文件永久关闭 $ syste ...

  4. MySQL系列:MySQL的基本使用

    数据库的基本操作 在MySQL数据库中,对于一个MySQL示例,是可以包含多个数据库的. 在连接MySQL后,我们可以通过 show databases; 来进行查看有那么数据库.这里已经存在一些库了 ...

  5. Python 面向对象之五 基础拾遗

    Python 面向对象之五 基础拾遗 今天呢,就剩下的面向对象的相关知识进行学习,主要会学习以下几个方面的知识:1.上下文管理协议,2.为类加装饰器 3.元类 一.上下文管理协议 在学习文件操作的时候 ...

  6. 20190806-sed面试题

    由于比较难,附上PPT,没事还得看 下载:https://www.lanzous.com/i5cs9aj 密码:arka 1.删除centos7系统/etc/grub2.cfg⽂件中所有以空⽩开头的⾏ ...

  7. ASP.NET Core 1.0: 指定Default Page

    前不久写过一篇Blog<指定Static File中的文件作为Default Page>,详细参见链接. 然而,今天偶然发现了一个更加简洁的方法,直接使用Response的Redirect ...

  8. ZeroC ICE中的对象

    在ZeroC Ice中定义了三种基本对象类型. 它们分别是IceProxy::Ice::Object(于Ice/Proxy.h),Ice::Object(于Ice/Object.h)和Ice::Loc ...

  9. Mac的Safari安装油猴插件(Tampermonkey)

    Mac的Safari安装油猴插件(Tampermonkey) 官方的AppStore是没有油猴插件(Tampermonkey)的,官方插件不仅少,功能被阉割,相对弱小,还收费.嗯,这很苹果第三方拓展. ...

  10. kali下安装phpstudy

    只需要用到三条命令就可完成,具体如下: wget -c http://lamp.phpstudy.net/phpstudy.bin chmod +x phpstudy.bin #权限设置 ./phps ...