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& ...
随机推荐
- 使用Typescript重构axios(六)——实现基础功能:获取响应数据
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- javascript腾讯地图放到网页中的方法
1 输入地址获取经纬度 http://lbs.qq.com/tool/getpoint/2 修改url https://apis.map.qq.com/uri/v1/marker?marker=coo ...
- H5+app -- 关于ajax提交问题
1.前阵子在做系统的h5+ app为满足手机端也能进行业务操作,例如:提货,扫描入库之类的.所以就要将做接口,从手机端调用后台系统的方法. 2.例如这样的请求格式,但是呢,每次请求它都直接跳到erro ...
- Servlet中response的相关案例(重定型,验证码,ServletContext文件下载)
重定向 首先设置状态码,设置响应头 //访问Demo1自动跳转至Demo2 //设置状态码 response.setStatus(302); //设置响应头 response.setHeader(&q ...
- 虚幻4 UE4 蓝图之关卡蓝图实现自动开关门
新建项目 往关卡中放置一个门 在内容浏览器中找到 门 的静态网格体 拖放到关卡中 此时门默认没有碰撞,人物可以直接穿过 给门添加碰撞 双击内容管理器中的 SM_Door,打开编辑窗口 选择菜单&quo ...
- hdu 2554 最短路 (dijkstra)
最短路Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submissi ...
- ZeroC ICE中的对象模型和概念
Ice对象的模型和概念. Ice Object并非是我们的接口实现类的实例对象.我们的接口实现类的实例对象只是充当Ice Object的Servant的角色.一个Ice Object可以有众多Serv ...
- Maven 无法下载依赖包的解决方法---三步dao!!!
版权声明:本文为博主原创文章,转载请附上原文出处链接和本声明. 本文链接:https://www.cnblogs.com/WLCYSYS/p/11932157.html maven 自动下载依赖包出现 ...
- [FPGA]Verilog实现8位串并转换器HC595
目录 想说的话... 正文 IC介绍_HC595 电路连接图 功能表 逻辑图 代码实现 代码已经更新,新的代码按照电路编写,忠实于原电路的逻辑,已注于文末(11/16) 修复并行输出数据出错的bug, ...
- Three.js - 走进3D的奇妙世界
本文将通过Three.js的介绍及示例带我们走进3D的奇妙世界. 文章来源:宜信技术学院 & 宜信支付结算团队技术分享第6期-支付结算部支付研发团队前端研发高级工程师-刘琳<three. ...