java——线段树 SegmentTree
应用:
区间染色
区间查询
线段树不是完全二叉树,线段树是平衡二叉树
使用数组来实现线段树:存储空间为4n
以下是使用数组实现的静态线段树:
- public class SegmentTree<E> {
- private E[] tree;
- private E[] data;
- private Merger<E> merger;
- public SegmentTree(E[] arr, Merger<E> merger) {
- this.merger = merger;
- data = (E[]) new Object[arr.length];
- for(int i = 0 ; i < arr.length ; i ++) {
- data[i] = arr[i];
- }
- tree = (E[]) new Object[4 * arr.length];
- buildSegmentTree(0, 0, data.length - 1);
- }
- //在tree Index的位置创建表示区间[l ... r]的线段树
- private void buildSegmentTree(int treeIndex, int l, int r) {
- if(l == r) {
- tree[treeIndex] = data[l];
- return;
- }
- int leftTreeIndex = leftChild(treeIndex);
- int rightTreeIndex = rightChild(treeIndex);
- int mid = l + (r - l) / 2;
- buildSegmentTree(leftTreeIndex, l, mid);
- buildSegmentTree(rightTreeIndex, mid + 1, r);
- //根据业务组合线段树
- tree[treeIndex] = merger.merge(tree[leftTreeIndex], tree[rightTreeIndex]);
- }
- public E get(int index) {
- if(index < 0 || index >= data.length) {
- throw new IllegalArgumentException("Index is illegal.");
- }
- return data[index];
- }
- public int getSize() {
- return data.length;
- }
- private int leftChild(int index) {
- return 2*index + 1;
- }
- private int rightChild(int index) {
- return 2*index + 2;
- }
- public E query(int queryL, int queryR) {
- if(queryL < 0 || queryL >= data.length || queryR < queryL){
- throw new IllegalArgumentException("Index is illegal.");
- }
- return query(0, 0, data.length -1, queryL, queryR);
- }
- //查询线段树
- //在以treeID为根的线段树中[l...r]的范围里,搜索区间[queryL...queryR]的值
- private E query(int treeIndex, int l, int r, int queryL, int queryR) {
- if(l == queryL && r == queryR) {
- return tree[treeIndex];
- }
- int mid = l + (r-l)/2;
- int leftTreeIndex = leftChild(treeIndex);
- int rightTreeIndex = rightChild(treeIndex);
- if(queryL >= mid +1) {
- return query(rightTreeIndex, mid + 1, r, queryL, queryR);
- }else if(queryR <= mid) {
- return query(leftTreeIndex, l, mid, queryL, queryR);
- }else {
- //这种情况下产生了两段线段树,需要进行融合
- E leftResult = query(leftTreeIndex, l, mid, queryL, mid);
- E rightResult = query(rightTreeIndex, mid + 1, r, mid + 1, queryR);
- return merger.merge(leftResult, rightResult);
- }
- }
- //将index位置的值更新为e
- public void set(int index, E e) {
- if(index < 0 || index >= data.length) {
- throw new IllegalArgumentException("Index is illegal");
- }
- data[index] = e;
- set(0,0, data.length - 1, index, e);
- }
- private void set(int treeIndex, int l, int r, int index, E e) {
- if(l == r) {
- tree[treeIndex] = e;
- return;
- }
- int mid = l + (r - l) / 2;
- int leftTreeIndex = leftChild(treeIndex);
- int rightTreeIndex = rightChild(treeIndex);
- if(index >= mid + 1) {
- set(rightTreeIndex, mid + 1, r, index, e);
- }else {
- set(leftTreeIndex, l, mid, index, e);
- }
- tree[treeIndex] = merger.merge(tree[leftTreeIndex], tree[rightTreeIndex]);
- }
- @Override
- public String toString() {
- StringBuilder res = new StringBuilder();
- res.append('[');
- for(int i = 0 ; i < tree.length ; i ++) {
- if(tree[i] != null) {
- res.append(tree[i]);
- }else {
- res.append("null");
- }
- if(i != tree.length - 1) {
- res.append(", ");
- }
- }
- res.append("]");
- return res.toString();
- }
- }
对于一个区间的更新:
懒惰更新:使用lazy数组记录未更新的内容,下一次访问时先访问lazy数组,若有内容,更新后再访问即可。
动态线段树:
使用链表实现
节省空间
可以不均等划分区间,便于实际应用
java——线段树 SegmentTree的更多相关文章
- [java线段树]2015上海邀请赛 D Doom
题意:n个数 m个询问 每个询问[l, r]的和, 再把[l, r]之间所有的数变为平方(模为9223372034707292160LL) 很明显的线段树 看到这个模(LLONG_MAX为922337 ...
- Java线段树
线段树不是完全二叉树,是平衡二叉树 堆也是平衡二叉树 堆满二叉树: h层,一共有2^h-1个节点(大约是2^h) 最后一层(h-1层)有2^(h-1)个节点 最后一层的节点数大致等于前面所有层节点之和 ...
- 模板 - 数据结构 - 线段树/SegmentTree
区间求加法和: 单点修改的,普通线段树. struct SegmentTree { #define ls (o<<1) #define rs (o<<1|1) static c ...
- 【LeetCode】线段树 segment-tree(共9题)+ 树状数组 binary-indexed-tree(共5题)
第一部分---线段树:https://leetcode.com/tag/segment-tree/ [218]The Skyline Problem [307]Range Sum Query - Mu ...
- 线段树(SegmentTree)基础模板
线段树模板题来源:https://www.lintcode.com/problem/segment-tree-build/description 201. 线段树的构造 /** * Definitio ...
- 【hihoCoder】第20周 线段树
题目: 输入 每个测试点(输入文件)有且仅有一组测试数据. 每组测试数据的第1行为一个整数N,意义如前文所述. 每组测试数据的第2行为N个整数,分别描述每种商品的重量,其中第i个整数表示标号为i的商品 ...
- java 操作格子问题(线段树)
很久之前做过线段树的问题(操作格子),时间长了之后再次接触到,发现当初理解的不是很透彻,然后代码冗长,再遇到的时候发现自己甚至不能独立地完成这个问题. 所以算法这个东西啊, 第一,是要经常练习(我个人 ...
- POJ——3264线段树
题目: 输入两个数(m,n),m表示牛的头数,n表示查询的个数.查询时输入两个数(x,y),表示查询范围的起始值和终止值,查询结果是,这个区间内牛重量的最大值减去牛重量的最小值,数量级为1000,00 ...
- lintcode:线段树的查询
线段树的查询 对于一个有n个数的整数数组,在对应的线段树中, 根节点所代表的区间为0-n-1, 每个节点有一个额外的属性max,值为该节点所代表的数组区间start到end内的最大值. 为Segmen ...
随机推荐
- IFC文档结构说明
工业基础类为代表的建筑信息BIM数据交换和共享在一个建筑或设施管理项目各参与者之间的开放规范的建模.IFC是国际openbim标准.本文件包含的IFC标准的规范.该规范包括的数据架构,表示为一个表达模 ...
- 205. Isomorphic Strings两个数组变形记,是否符合规则
[抄题]: Given two strings s and t, determine if they are isomorphic. Two strings are isomorphic if the ...
- const 和 #define区别
(1) 编译器处理方式不同 define宏是在预处理阶段展开. const常量是编译运行阶段使用. (2) 类型和安全检查不同 define宏没有类型,不做任何类型检查,仅仅是展开. const常量有 ...
- 两个进程之间的通讯——pipe 管道
在实际工作中,已经编辑好了NIPT_analysis的软件,该软件一般的输入文件是sam文件,但是为了集成进入测序仪器,需要直接从比对软件的标准输出中读取sam文件,省去了比对软件和NIPT_anal ...
- loj2395 [JOISC 2017 Day 2]火车旅行
传送门 分析 我们知道无论往左走还是往右走一定都是往不低于这个点的地方走 于是我们可以考虑用倍增来维护一个点向左和向右走$2^i$最远分别能走到哪里 我们可以先用单调栈求出直走一步的情况,之后再处理倍 ...
- Node.js 介绍及学习
Node.js => 简单来理解,就是指运行在服务器端的JavaScript. Node.js 是一个基于Chrome JavaScript运行时建立的一个平台 Node.js是一个事件驱动I ...
- Server.MapPath方法的应用方法
老是忘记Server.MapPath的使用方法了,下面记录一下,以备后用:总注:Server.MapPath获得的路径都是服务器上的物理路径,也就是常说的绝对路径1.Server.MapPath(&q ...
- Delphi和C#数据类型对应表
Delphi DataType C# datatype ansistring string boolean bool byte byte char char comp double currency ...
- vs code进行c/c++开发
vs code是微软公司开发的跨平台编辑器,丰富的插件功能可以满足各种编程语言的编码,编译和调试.由于vs code本身只是一个编辑器,所以你需要准备编译工具链.本文针对的是windows系统,我这里 ...
- javascript 常用兼容fire fox的解决办法
常用兼容fire fox的解决办法 一.js不兼容:1.event不兼容,必须通过参数传递过来: function test(event){ //兼容fire fox var event = even ...