[算法]线段树(IntervalTree)
转载请注明出处:http://www.cnblogs.com/StartoverX/p/4617963.html
线段树是一颗二叉搜索树,线段树将一个区间划分成一些单元区间,每一个区间对应线段树的一个叶节点。对于线段树的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。

线段树的特征:
1.线段树的长度不超过logL(L是最长区间的长度)。
2.线段树把区间上的任意一条线段都分成不超过2logL条线段。
这些结论为线段树能够在O(logL)时间内完成一条线段的插入,删除,查找等工作,提供了理论依据。
线段树的用途:
线段树适用于和区间统计有关的问题。比如某些数据可以按区间进行划分,按区间动态进行修改,而且还需要按区间多次进行查询,那么使用线段树可以达到较快查询速度。
数据结构:
typedef struct IntervalTree
{
int right;
int left;
IntervalTree* right_child;
IntervalTree* left_child;
/*other information*/
//通常为了解题需要记录其他的信息。
}IntervalTree;
在线段上建树:
IntervalTree* buildTree(int a,int b)
{
IntervalTree* tree = new IntervalTree;
tree->right = b;
tree->left = a;
tree->right_child = NULL;
tree->left_child = NULL;
if(b > a)
{
int mid = (a + b)/;
tree->right_child = buildTree(mid+,b);
tree->left_child = buildTree(a,mid);
}
return tree;
}
//通常线段上会记录其他的信息,需要在建树时同时记录到树的每一个node。
线段树通常引入为了解决关于区间的问题,在树中插入线段,删除线段,查询线段的方法都和具体问题有关,我们以下面的问题为例:
已知范围A1....An,在该范围内不断进行插入新线段(Ai...Aj,<=i<=j<=n),删除线段(Ai...Aj,<=i<=j<=n)的操作,最后求某个线段被覆盖的次数?
为了解决这个问题,我们在线段A1...An上建树,并且在线段树中保存被覆盖的次数cover。
数据结构:
typedef struct IntervalTree
{
int right;
int left;
int cover;//保存被覆盖的次数。
IntervalTree* right_child;
IntervalTree* left_child;
}IntervalTree;
建树:
IntervalTree* buildTree(int a,int b)
{
IntervalTree* tree = new IntervalTree;
tree->right = b;
tree->left = a;
tree->cover = ;//初始时cover为0
tree->right_child = NULL;
tree->left_child = NULL;
if(b > a)
{
int mid = (a + b)/;
tree->right_child = buildTree(mid+,b);
tree->left_child = buildTree(a,mid);
}
return tree;
}
插入新线段:
void insert(int a,int b,IntervalTree* tree)
{
if(tree->right == b && tree->left == a)
{
tree->cover++;
return;
}
int mid = (tree->left + tree->right)/;
if(a > mid)
{
insert(a,b,tree->right_child);
}
else if(b <= mid)
{
insert(a,b,tree->left_child);
}
else
{
insert(a,mid,tree->left_child);
insert(mid+,b,tree->right_child);
}
}
删除线段:
void delete_interval(int a,int b,IntervalTree* tree)
{
if(tree->right == b && tree->left == a)
{
tree->cover--;
return;
}
int mid = (tree->left + tree->right)/;
if(a > mid)
{
delete_interval(a,b,tree->right_child);
}
else if(b <= mid)
{
delete_interval(a,b,tree->left_child);
}
else
{
delete_interval(a,mid,tree->left_child);
delete_interval(mid+,b,tree->right_child);
}
}
查询线段覆盖次数:
int query(int a,int b,IntervalTree* tree)
{
if(tree->right == b && tree->left == a)
{
return tree->cover;
}
int mid = (tree->right + tree->left)/;
if(a > mid)
{
return tree->cover + query(a,b,tree->right_child);
}
else if(b <= mid)
{
return tree->cover + query(a,b,tree->left_child);
}
else
{
int cover_right = query(mid+,b,tree->right_child);
int cover_left = query(a,mid,tree->left_child);
return tree->cover + ((cover_right > cover_left) ? cover_right : cover_left);
}
}
线段树应用举例:POJ 3264:Balanced Lineup:http://www.cnblogs.com/StartoverX/p/4618041.html
[算法]线段树(IntervalTree)的更多相关文章
- [莫队算法 线段树 斐波那契 暴力] Codeforces 633H Fibonacci-ish II
题目大意:给出一个长度为n的数列a. 对于一个询问lj和rj.将a[lj]到a[rj]从小到大排序后并去重.设得到的新数列为b,长度为k,求F1*b1+F2*b2+F3*b3+...+Fk*bk.当中 ...
- 浅谈算法——线段树之Lazy标记
一.前言 前面我们已经知道线段树能够进行单点修改和区间查询操作(基本线段树).那么如果需要修改的是一个区间该怎么办呢?如果是暴力修改到叶子节点,复杂度即为\(O(nlog n)\),显然是十分不优秀的 ...
- C++算法 线段树
线段树这个算法,看起来非常高端,而且很有用处,所以还是讲一下下吧. 温馨提示:写线段树前请做好写码5分钟,调试一辈子的准备^-^ 啊直接步入正题…… 首先我们考虑一个题目:有一个序列,要做到单点修改单 ...
- POJ 3368 Frequent values RMQ ST算法/线段树
Frequent values Time Limit: 2000MS Memory Lim ...
- [bzoj4372] 烁烁的游戏 [动态点分治+线段树+容斥原理]
题面 传送门 思路 观察一下题目,要求的是修改"距离点$u$的距离一定的点权值",那这个就不能用传统的dfs序类算法+线段树维护,因为涉及到向父亲回溯的问题 看到和树上距离相关的东 ...
- 算法手记 之 数据结构(线段树详解)(POJ 3468)
依然延续第一篇读书笔记,这一篇是基于<ACM/ICPC 算法训练教程>上关于线段树的讲解的总结和修改(这本书在线段树这里Error非常多),但是总体来说这本书关于具体算法的讲解和案例都是不 ...
- RMQ问题(线段树+ST算法)
转载自:http://kmplayer.iteye.com/blog/575725 RMQ (Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ ...
- nyoj 119士兵杀敌(三)(线段树区间最值查询,RMQ算法)
题目119 题目信息 执行结果 本题排行 讨论区 士兵杀敌(三) 时间限制:2000 ms | 内存限制:65535 KB 难度:5 描写叙述 南将军统率着N个士兵,士兵分别编号为1~N,南将军常 ...
- 线段树:CDOJ1591-An easy problem A (RMQ算法和最简单的线段树模板)
An easy problem A Time Limit: 1000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Pr ...
随机推荐
- 由“Beeline连接HiveServer2后如何使用指定的队列(Yarn)运行Hive SQL语句”引发的一系列思考
背景 我们使用的HiveServer2的版本为0.13.1-cdh5.3.2,目前的任务使用Hive SQL构建,分为两种类型:手动任务(临时分析需求).调度任务(常规分析需求),两者均通过我们的 ...
- 【贪心+堆】XMU 1584 小明的烦恼
题目链接: http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1584 题目大意: 给n(n<=100 000)个任务的耗时和截至时间,问最少不能 ...
- Java 8 中新的 Date 和 Time 类入门详解
这篇文章主要是java8中新的Date和Time API的实战.新的Date和Time类是java开发者社区千呼万唤始出来的.Java8 之前存在的Date类一直都受人诟病,很多人都会选择使用第三方的 ...
- Oracle执行计划——all_rows和first_rows(n) 优化器模式
0. 环境创建 SQL> create usertest identified by test 2 default tablespace users 3 temporary tablespace ...
- 港股street和nominee区别
股票的street和nominee区别主要用在公司行动的过户费方面,street股票需要收取过户费,nominee不收过户费. street股票通过做公司行动收取过户费后会变成nominee股票,下次 ...
- Sublime代码折叠
一.显示折叠小三角 1.点击Sublime的Preferences->Setting-Default菜单,打开它的配置文件. 2.找到行 // Fold buttons are the tria ...
- iOS--导航栏样式
push返回按钮样式: UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBar ...
- C++中的构造函数和析构函数
构造函数: 在类实例化对象时自动执行,对类中的数据进行初始化.构造函数可以从载,可以有多个,但是只能有一个缺省构造函数. 析构函数: 在撤销对象占用的内存之前,进行一些操作的函数.析构函数不能被重载, ...
- Android(java)学习笔记251:ContentProvider使用之添加数据到联系人(掌握)
1.添加联系人逻辑思路 (1)首先在raw_contacts创建一个新的id (2)在data表里面添加这个id对应的数据 2.下面通过一个案例,说明一下如何添加一条数据到联系人: (1)首先我们关注 ...
- UVA 11770 Lighting Away
RunID User Problem Result Memory Time Language Length Submit Time 2482977 zhyfzy J Accepted 0 KB 138 ...