线段树是ACM中比较常见的数据结构,它的每一点都代表了一条线段[a,b],长度为1的为元线段,所有叶子结点的长度均为1。长度范围为[1,L]的一颗线段树的深度为log(L-1)+1。
线段树基本的应用时查询某段的和,最大最小值,成段更新,保证每次操作的复杂度为log(n)。
关于线段树的文章有很多,大家可以参考http://www.notonlysuccess.com/?p=59。
在这里,我用hdu和poj上面的一些关于线段树的简单应用做为例题讲解。
hdu1166(单点更新,区间求和):
敌军海岸线上排列有n个营地,每个营地有若干个士兵,每个营地的士兵都是在随时变动(增加或减少),要随时求出任意两个营地之间的士兵人数之和。
首先构造线段树的结构:
struct Seg_Tree
{
int left;//左孩子
int right;//右孩子
int value; //该段士兵的总人数
int calmid()
{
return (left+right)>>1;
}
}tt[MAX*4];//MAX是营地个数,一般线段树的结点为它的4倍
然后就是创建线段树:
int build(int left,int right,int idx)//idx从1开始
{
tt[idx].left = left;
tt[idx].right = right;
if(left == right)
return tt[idx].value = num[left];
int mid = (left + right)>>1;
return tt[idx].value = build(left,mid,LL(idx)) + build(mid+1,right,RR(idx));
}
对于某个营地增加或减少士兵,有更新操作:
void update(int id,int x,int idx)
{
tt[idx].value += x;
if(tt[idx].left == tt[idx].right)
return;
int mid = tt[idx].calmid();
if(id <= mid)
update(id,x,LL(idx));
else
update(id,x,RR(idx));
}
查询某段营地士兵数量总和:
int query(int left,int right,int idx)
{
if(left == tt[idx].left && right == tt[idx].right)
return tt[idx].value;
int mid = tt[idx].calmid();
if(right <= mid)
return query(left,right,LL(idx));
else if(mid < left)
return query(left,right,RR(idx));
else
return query(left,mid,LL(idx)) + query(mid+1,right,RR(idx));
}
hdu1754(单点更新,区间最值):
老师喜欢问学生a到学生b中最好的成绩是多少,其间,还会更改某些学生的成绩。
创建线段树:
int bulid(int left, int right, int idx)
{
tt[idx].left = left;
tt[idx].right = right;
if(left == right)
return tt[idx].value = num[left];
int mid = tt[idx].calmid();
return tt[idx].value = max(bulid(left,mid,LL(idx)), bulid(mid+1,right,RR(idx)));
}
对于某个学生成绩的更改,有更新操作:
void update(int id, int value, int idx) //更新点,同时更新区间最值:先更新左右子树的最值,然后更新父节点
{
if(tt[idx].left == tt[idx].right)
{
tt[idx].value = value;
return;
}
int mid = tt[idx].calmid();
if(id <= mid)
update(id,value,LL(idx));
else
update(id,value,RR(idx));
tt[idx].value = max(tt[LL(idx)].value, tt[RR(idx)].value);
}
查询某段学生成绩中的最大值:
int query(int left, int right, int idx)
{
if(left == tt[idx].left && right == tt[idx].right)
return tt[idx].value;
int mid = tt[idx].calmid();
if(right <= mid)
return query(left,right,LL(idx));
else if(left > mid)
return query(left,right,RR(idx));
else
return max(query(left,mid,LL(idx)), query(mid+1,right,RR(idx)));
}
以上两道例题是对于单点更新,对于成段更新,有hdu1698:
dota里面有一种钩子,它由n段组成,刚开始全部是铜的,每段重量为1。现在要把其中a-b这段换成金的或者银的(重量分别为3,2),查询这个钩子的总重量。
创建线段树:
void build(int left, int right, int idx)
{
tt[idx].left = left;
tt[idx].right = right;
tt[idx].value = 1;//初始每段重量为1,-1表示这段钩子中是混合的(金银铜的混合)
if(left == right)
return;
int mid = (left + right)>>1;
build(left,mid,LL(idx));
build(mid+1,right,RR(idx));
}
更新a-b段的钩子:
void update(int left, int right, int value, int idx) //更新区间
{
if(left <= tt[idx].left && right >= tt[idx].right)
{
tt[idx].value = value;
return;
}
if(tt[idx].value != -1)
{
tt[LL(idx)].value = tt[RR(idx)].value = tt[idx].value;
tt[idx].value = -1; //表示这个点代表的线段是混合的
}
int mid = tt[idx].calmid();
if(left <= mid)
update(left,right,value,LL(idx));
if(mid < right)
update(left,right,value,RR(idx));
}
查询某段钩子的重量:
int query(int left, int right, int idx)
{
if(left == tt[idx].left && right == tt[idx].right)
{
if(tt[idx].value != -1)
return (right-left+1)*tt[idx].value;
else
{
int mid = tt[idx].calmid();
return query(left,mid,LL(idx)) + query(mid+1,right,RR(idx));
}
}
int mid = tt[idx].calmid();
if(right <= mid)
return query(left,right,LL(idx));
else if(left > mid)
return query(left,right,RR(idx));
else
return query(left,mid,LL(idx)) + query(mid+1,right,RR(idx));
}
学习线段树,要熟悉线段树的构造,查找,更新操作。
分享到:
相关推荐
### 统计的力量——线段树全接触 #### 引言 线段树作为一种高效的数据结构,在算法竞赛中尤其受到重视。它不仅适用于区间查询,还能处理动态更新问题,是解决许多复杂问题的关键工具之一。张昆玮老师的《统计的力量...
线段树——在ACM中制胜的法宝 线段树是一种非常重要的数据结构,广泛应用于算法竞赛(ACM)和实际编程中。线段树可以高效地解决许多问题,如区间查找、区间更新、区间统计等。但是,对于线段树的理解和应用,需要对...
线段树,有时也被称为区间树,是一种高效的数据结构,主要用于处理区间查询和区间更新的问题。它通过将一个大的区间划分为若干个较小的、互不重叠的子区间来实现这一功能。下面我们将详细介绍线段树的基本定义及其...
内容概要:本文详细介绍了一种高级数据结构——线段树(Segment Tree),主要探讨了它的实现方法及其在区间查询与更新问题中的应用,包括具体实现的Python代码片段。 适合人群:对数据结构有基本认识的程序员或数据...
线段树是一种高效的数据结构,主要用于处理区间查询和区间更新问题。它通过将一个大的区间细分成若干个较小的不重叠的子区间来实现高效的区间操作。在计算机科学领域,尤其是在算法竞赛中,线段树是非常重要的工具之...
线段树是一种高效的数据结构,常用于解决动态统计问题,特别是在计算机科学和算法设计中。它的主要作用是在一组数据上支持快速的区间查询和修改。线段树通过将线段分解为更小的子线段并存储在二叉树结构中,能够实现...
线段树是一种高效的数据结构,主要用于处理区间查询与更新问题,尤其在计算机科学中的算法设计中扮演着重要角色。清华大学的这份讲义是深入理解线段树的优质资源,它涵盖了线段树的基础理论、实现细节以及应用实例,...
"动态序列与动态树问题——浅谈几种常用数据结构" 本文主要讨论了动态序列问题和动态树问题的解决方法,通过介绍了几种常用的平衡二叉树型数据结构来解决这些问题。动态序列问题是指在一个序列上执行一系列在线操作...
线段树是一种高效的数据结构,广泛应用于解决与区间查询和修改相关的编程问题。在IT行业中,熟悉线段树是提高算法能力、优化代码性能的重要手段。这篇博客文章“线段树(一)——概念和应用”可能深入浅出地介绍了...
线段树是一种高效的数据结构,常被用于处理区间查询或更新的问题。它是一棵二叉树,其中每个节点代表一个特定的区间。具体来说: - **叶子节点**:代表一个单位区间,即形式为`[i, i]`的区间。 - **非叶子节点**:...
本文将深入探讨线段树的概念,特别是其动态版本——**动态线段树**(Dynamic Segment Tree),以及一种创新的数据结构——**并集复制结构**(Union-Copy Structure),该结构为动态线段树的实现提供了坚实的基础。...
### ACM培训课件知识点解析——线段树 #### 一、线段树概念与作用 线段树是一种高效的数据结构,用于存储和处理连续区间上的数据。它通过将区间分割成若干子区间,并在树的节点上存储这些子区间的相关信息,从而...
本主题“刷题算法提高阶段-数据结构4”将着重于一个特殊的数据结构——线段树,它是处理区间查询和更新问题的有效工具。线段树是一种树形数据结构,用于高效地维护一段连续区间的信息,如区间求和、查找最值等操作。...
3. **正交范围查询结构**:用于多维空间中进行快速查询的数据结构,如矩形范围查询、线段树等。 4. **堆**:一种特殊形式的完全二叉树结构,常用于实现优先队列等。 5. **并查集(Union-Find Structures)**:一...
线段树是一种用于处理区间查询和更新问题的数据结构。它通过构建一颗具有特定结构的二叉树来实现对区间数据的有效管理和操作。具体而言,线段树能够高效地支持区间上的查询(如求和、最大值等)和更新操作(如增加、...
在计算机科学领域,特别是在算法设计与分析方面,**线段树**是一种非常重要的数据结构,它能够高效地支持区间查询和更新操作。本文档主要介绍了线段树在解决特定类型问题时的应用,特别是那些不再仅仅是NOIP级别(即...