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& ...
随机推荐
- 『题解』洛谷P3384 【模板】树链剖分
Problem Portal Portal1: Luogu Description 如题,已知一棵包含\(N\)个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作\(1\): ...
- Java环境变量配置教程
Windows 10 Java环境变量配置教程 目前Windows 10系统已经很成熟,大多数人开发都在Windows 10系统下进行开发,于是乎我做一下Java环境变量在Windows 10配下的 ...
- VUE 表格进入页面加载初始数据及操作后刷新数据
1.获取列表数据方法 2.打开页面默认加载数据 3.操作后重新获取数据
- 开启docker中的mongodb认证授权
前言: 开启MongoDB服务后,默认是没有权限验证的.直接通过IP加端口就可以远程访问数据库,并对数据库进行任意操作.下面介绍一下如何开启docker中MongoDB的权限认证. 安装完MongoD ...
- csp-s2019游记
11.15D0: 复习 复习 机房里弥漫着颓废的气息,不过也是最后一个下午了 11.16D1: 五点钟爬起来,一边发抖一边去楼下买早饭 虽然平时基本不吃早饭,但考前不行 搭着同学的车去了考点,在车上重 ...
- Conda/Miniconda/Anaconda 常用命令整理及介绍
作者:HELO 出处:http://www.cnblogs.com/HELO-K 欢迎转载, 转载时请保留此声明, 谢谢! 在这里整理一份全一点的 Conda 常用命令, 方便大家日常使用时参考, 一 ...
- 网站搭建-2-本地网站搭建-安装Linux虚拟机/ 安装IIS Windows
搭建网站-1-域名申请参见公众号 生物信息系统(swxxxt) 首先,已经拥有了一个可以正常使用的域名. 之前买了两年的阿里的服务器,由于是Windows的,最后不了了之了(因为当时找的代码都是lin ...
- PHP 面试踩过的坑
1.get,post 的区别 **显示有区别 ** get方法是将字符串拼接在地址栏后面可以看见 而post方法看不见 **传递的大小有区别 ** 具体大小和浏览器有关系,ie浏览器是2k其他浏览器的 ...
- 【Elasticsearch 7 探索之路】(三)倒排索引
上一篇,我们介绍了 ES 文档的基本 CURE 和批量操作.我们都知道倒排索引是搜索引擎非常重要的一种数据结构,什么是倒排索引,倒排索引的原理是什么. 1 索引过程 在讲解倒排索引前,我们先了解索引创 ...
- hdu 5495 LCS (置换群)
Sample Input231 2 33 2 161 5 3 2 6 43 6 2 4 5 1 Sample Output24 C/C++: #include <map> #includ ...