线段树笔记√

线段树上的每一点表示一段区间和。



建树

首先,递归进去做,递归的参数是pos,l,r,分别表示,线段树上节点的编号(即当前编号),以及这个点表示的区间的左端点和右端点。那么终止的条件就是l=r,这个时候,node[pos].sum=a[l]

我们考虑一下l不等于r的时候,那么这个区间的左儿子就是[l,mid],右儿子就是[mid+1,r]

然后考虑一下左边儿子的节点编号是什么

我们之间令编号为x的节点的左儿子为x*2,右儿子为x*2+1

那么只有对左右儿子递归进去做就行了,做完了之后,我们更新一下sum

【注意】线段树的节点个数要开成序列长度的四倍

 1 struct data{
 2     int sum;
 3 }node[400001];
 4 void build(int pos,int l,int r)
 5 {
 6     if(l==r){
 7         node[pos].sum=a[l];
 8         return;
 9     }
10     int mid=l+r>>1;//µÈ¼Û(l+r)/2,λÔËËãÓÅÏȼ¶×îµÍ
11     int lson=pos*2,rson=pos*2+1;
12     build(lson,l,mid);
13     build(rson,mid+1,r);
14     node[pos].sum=node[pos*2].sum+node[pos*2+1].sum;
15 }

建树



查询

比如说,你要查区间[5,6]的和,你会发现,这就是线段树上的一个节点,那直接找到这个节点就行。

//pos表示当前走到了哪个节点,l,r,表示这个节点所代表的区间,ql,qr表示你要查询的区间

我们考虑一下终止条件,是l=ql,r=qr。这个时候我们就可以直接返回node的信息,考虑一下如果不是,有哪些情况,首先我们先算出当前这段区间的中点,考虑一下,如果qr<=mid,那么我们要查询的区间都在左儿子里,这时候直接返回查询左儿子的值就行了。

还有什么情况呢,如果ql>mid,那是不是整个区间都在右儿子里,这时候就直接查右儿子就行了。

那考虑一下,如果查询的区间是一部分在左儿子里,一部分在右儿子里,要怎么办?

我们把查询的区间切开,原本要查[ql,qr],现在变成[ql,mid]+[mid+1,qr],那就是在左儿子里查询[ql,mid],在右儿子里查询[mid+1,qr]

1 int query(int pos,int l,int r,int ql,int qr)
2 {
3     if(l==ql&&r==qr)return node[pos].sum;
4     int mid=l+r>>1,lson=pos*2,rson=pos*2+1;
5     if(qr<=mid)return query(lson,l,mid,ql,qr);
6     else if(ql>mid) return query(rson,mid+1,r,ql,qr);
7     else return           query(lson,l,mid,ql,mid)+query(rson,mid+1,r,mid+1,qr);
8 }

查询



修改

修改有两种情况,单点修改和区间修改。

单点修改:首先还是pos表示当前节点,l,r表示当前节点代表的区间,m表示要修改的位置,显然递归终止的条件是l=r。那考虑一下,其实一个点,要么在mid左边 要么在mid右边,直接判断一下在哪边递归进去做就行了

如果l=r,说明找到这个点了,sum+=v,然后退出

否则的话判断m是不是<=mid

是的话说明在左儿子里,递归下去修改。

不是的话,反之(模仿上述处理)

修改完了之后要注意,要记得更新节点的信息,这个点的和等于左儿子的和加上右儿子的和。

 1 int modify_dot(int pos,int l,int r,int m,int v)
 2 {
 3     if(l==r){
 4         node[pos].sum
 5         return;
 6     }
 7     int mid=l+r>>1,lson=pos*2,rson=pos*2+1;
 8     if(m<=mid)modify_dot(lson,l,mid,m,v);
 9     else modify_dot(rson,mid+1,r,m,v);
10     node[pos].sum=node[lson].sum+node[rson].sum;
11
12 }

修改



e.g.

先给你n,m表示序列长度,和操作次数,接下来n个数,表示原序列,接下来m行,表示操作
如果输入格式是1 l r
表示查询l到r的和
如果输入格式是2 l r
表示查询l到r的最小值
如果输入格式是3 l r
表示查询l到r的最大值
如果输入格式是4 m v
表示序列中第m个数变成v

时间: 2024-08-27 02:06:19

线段树笔记√的相关文章

《ACM/ICPC 算法训练教程》读书笔记 之 数据结构(线段树详解)

依然延续第一篇读书笔记,这一篇是基于<ACM/ICPC 算法训练教程>上关于线段树的讲解的总结和修改(这本书在线段树这里Error非常多),但是总体来说这本书关于具体算法的讲解和案例都是不错的. 线段树简介 这是一种二叉搜索树,类似于区间树,是一种描述线段的树形数据结构,也是ACMer必学的一种数据结构,主要用于查询对一段数据的处理和存储查询,对时间度的优化也是较为明显的,优化后的时间复杂为O(logN).此外,线段树还可以拓展为点树,ZWK线段树等等,与此类似的还有树状数组等等. 例如:要将

线段树学习笔记

线段树学习笔记 20180112 http://www.cnblogs.com/wuyuanyuan/p/8277100.html 一定要明确需要维护的值(区间最大值.区间和--). 原文地址:https://www.cnblogs.com/wuyuanyuan/p/8278004.html

【线段树】学习笔记

线段树,顾名思义就是用来存储线段的结构.利用这个,我们可以将一个线段(区间)上的统计问题在log2n时间内解决 这里以n为2的幂的情况做讨论 线段树的层数最多为log2n层:线段树的叶子节点表示的是一个『点』,那么n,每次除以二,显然在第log2n层会变成叶子节点,所以层数只会有log2n层 每个线段可以被分为2log2L条:考虑查询的连续性,如果你在某一层取得两个结点,它们肯定是不相邻的,显然我们取不到同一层的第三个结点,所以每个线段可以被分为2log2L条 Lazy-tag技术:应对区间修改

学习笔记:可持久化线段树

1.前言 线段树,众所周知,在树中的每一个元素中,保存的是线段中的一段,所维护的内容或是最大最小值,或是和等等.可持久化线段树,属于可持久化数据结构中的一种,对于可持久化数据结构这个大知识,我暂时没有去研究,今天只讲其冰山一角. 2.概念 先讲”可持久化“的含义.”可持久化“表示我们当前在处理每个状态,而之前的状态即状态的历史版本全部能够存下来.可持久化线段树,实质上是多颗线段树,最简单的可持久化线段树的题目:求区间第k大.显而易见,求区间最大值的时候我们用普通的线段树就行了,第k大总不能一个个

【线段树四】HDU 2795 Billboard

BillboardTime Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 9045    Accepted Submission(s): 4021 Problem Description At the entrance to the university, there is a huge rectangular billboard of siz

【简单线段树】I Hate It (求范围内最大)

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 53477    Accepted Submission(s): 21005 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感.不管你喜不喜欢,现在需要你做的是,就是按照老师的

线段树入门---给定多个线段求点的出现个数

线段树是一颗二叉树,他的每个节点都是一个区间,此题为线段树的入门题目,只是学习笔记.例题:给定N个线段,给定M个点,求点在多少个线段中出现过,此时如果用传统的方法来求,时间复杂度太高,但是,线段树的时间复杂度还可以接受. 步骤为: 1. 首先找一个区间,能覆盖给定的所有区间, 然后把此区间建立线段树,建立线段树的方式是二分法建立,即它的左孩子是他的左半个区间,右孩子是它的右边那个区间.一个图足以说明清楚 2. 将所有的区间映射到此树上, 从根节点开始遍历, 每遍历一个节点考虑四种情况: 1) 当

【线段树】HDU 1394 Minimum Inversion Number

minimum inversion number:最小逆序数 Minimum Inversion NumberTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 9367    Accepted Submission(s): 5754 Problem Description The inversion number of a given nu

【线段树一】HDU 1166 敌兵布阵

敌兵布阵Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 37406    Accepted Submission(s): 15774 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是