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& ...
随机推荐
- 利用bootstrap3的分页样式和jq实现分页功能
1源码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...
- 问题 A: 雷神领域
传送门 题目描述 L君,S大陆首屈一指的天才魔法师,创造了一个新魔法:雷神领域. 这个魔法会首先在地面上形成正方网格魔法阵列,然后在某些位置召唤雷电轴标.注意:一个位置只能有一个雷电轴标存在. 雷电 ...
- day 2 DP专场
上午讲了一上午背包,从01背包到完全背包到多重背包,感觉也没说什么,旁边的大佬一直在飞鸽里说让老师讲快点,然而最后也没人敢跟老师说.... 例题真的各个都是神仙题, 挂饰 好像就是一上午最简单的... ...
- Css3动画-@keyframes与animation
一.@keyframe 定义和用法 @keyframes是用来创建帧动画的,我们通过这个属性可以用纯css来实现一些动画效果. 一般格式是: @keyframes 动画名称{ 0%{ 动画开始时的样式 ...
- git 合并代码
分支 dev 及衍生分支 dev-ctj 一.rebase 1.git checkout dev-ctj 2.git rebase -i head~num[num 是本分支的提交数,多个提交数先合并为 ...
- beacon帧字段结构最全总结(三)——VHT字段总结
VHT Capabilities 802.11ac作为IEEE 无线技术的新标准,它借鉴了802.11n的各种优点并进一步优化,除了最明显的高吞吐特点外,不仅可以很好地兼容802.11a/n的设备,同 ...
- SpringBoot 源码解析 (二)----- Spring Boot精髓:启动流程源码分析
本文从源代码的角度来看看Spring Boot的启动过程到底是怎么样的,为何以往纷繁复杂的配置到如今可以这么简便. 入口类 @SpringBootApplication public class He ...
- .NET进阶篇06-async异步、thread多线程2
知识需要不断积累.总结和沉淀,思考和写作是成长的催化剂 内容目录 一.线程Thread1.生命周期2.后台线程3.静态方法1.线程本地存储2.内存栅栏4.返回值二.线程池ThreadPool1.工作队 ...
- nyoj 77-开灯问题 (倍数遍历)
77-开灯问题 内存限制:64MB 时间限制:3000ms 特判: No 通过数:13 提交数:24 难度:1 题目描述: 有n盏灯,编号为1~n,第1个人把所有灯打开,第2个人按下所有编号为2 的倍 ...
- 爬虫多线程模板,xpath,etree
class QuiShi: def __init__(self): self.temp_url = "http://www.lovehhy.net/Joke/Detail/QSBK/{0}& ...