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& ...
随机推荐
- 实验:基于http的yum源
实验:基于http的yum源 selinux,firewalld已经关闭',系统为CentOS7 repodata所在的目录就是yum源 下面介绍了如何把本地光盘通过httpd服务器变成yum源:多个 ...
- 【R语言学习笔记】 Day1 CART 逻辑回归、分类树以及随机森林的应用及对比
1. 目的:根据人口普查数据来预测收入(预测每个个体年收入是否超过$50,000) 2. 数据来源:1994年美国人口普查数据,数据中共含31978个观测值,每个观测值代表一个个体 3. 变量介绍: ...
- 大宇java面试系列(三):Redis常见面试题
1. Redis 是什么?都有哪些使用场景? 我们先来理解经典的CAP理论: 一致性:是指从数据层面来看的一致性. 可用性:是指从系统层面的可用性. 容错性:是指从网络层面的的容错性. 数据库逐渐从关 ...
- java笔试面试第一天
好久未曾启用我的博客,最近来上海找工作,想将笔试面试的过程做个记录,毕竟有总结才有提高嘛.今天算是笔试面试正式开始第一天吧,以下就是我的笔试总结(没有原题了,只有知识点): 笔试题1:java sta ...
- lqb 基础练习 数列排序 (sort的使用)
基础练习 数列排序 时间限制:1.0s 内存限制:512.0MB 问题描述 给定一个长度为n的数列,将这个数列按从小到大的顺序排列.1<=n<=200 输入格式 第一行为一个整 ...
- lqb 入门训练 Fibonacci数列 (循环 PS:提柜要栈溢出)
入门训练 Fibonacci数列 时间限制:1.0s 内存限制:256.0MB 问题描述 Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1. 当n比较大时, ...
- 力扣(LeetCode)字符串中的第一个唯一字符 个人题解
给定一个字符串,找到它的第一个不重复的字符,并返回它的索引.如果不存在,则返回 -1. 案例: s = "leetcode" 返回 0. s = "loveleetcod ...
- flex一些属性
// 改变主轴的方向 flex-direction: column; // display:flex的子元素无法设置宽度 // 子元素有个flex-shrink属性,表示在父元素宽度不够的情况下是否自 ...
- LinearLayout适配不同机型技巧
<View android:layout_width="match_parent" android:layout_height="0dp" android ...
- python3 之 判断闰年小实例
一.方法1: while True: try: year = int(input('请输入一个年份:')) if (year % 4) == 0 and (year % 100) != 0 or (y ...