线段树初步__ZERO__.
来源:互联网 发布:淘宝服装挂拍技巧 编辑:程序博客网 时间:2024/06/05 02:50
线段树,顾名思义,就是指一个个线段组成的树。
线段树的定义就是:
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。
——摘自百度百科
如图,这就是一棵线段树:
那么线段树有哪些神奇的性质呢?
1.它是一棵满二叉树
2.每一个节点(一段区间)是它的两个子节点的并或最大值(RMQ)。
3.(因为线段树是满二叉树)树的空间复杂度是O(2N);
线段树例题
线段树的树结构:
此处我用一个一维的数组seg[node]表示节点为node所划分到的区间的值。
线段树的建树:
因为线段树是一棵满二叉树,所以可以采用递归的方式来实现储存。
code:
void build(int l,int r,int node){ if(l==r)seg[node]=a[l];//a[i]表示读入数列的第i个数 else { int mid=(l+r)>>1; build(l,mid,node*2); build(mid+1,r,node*2+1); up(node);//见下 } return ;}
此处需要介绍一个up(node)函数。
这是用于对这个节点的区间值进行更新。
code:
void up(int node){seg[node]=seg[node*2]+seg[node*2+1];}
建完树,但我们还需要做一些其他的操作,比如说区间查询(区间求和)或区间修改等。
所以我们就先介绍区间查询。
//L、R:目前访问区间的左右节点,ql,qr:查询区间的左右节点,node:当前节点的编号。
code:
int query(int l,int r,int ql,int qr,int node){ if(l>=ql&&r<=qr)return seg[node];//① else { int mid=(l+r)>>1; down(mid-l+1,r-mid,node);//② int ans=0; if(ql<=mid)ans+=query(l,mid,ql,qr,node*2);//③ if(qr>mid) ans+=query(mid+1,r,ql,qr,node*2+1); return ans; }}
①:因为线段树的节点表示一段区间,所以只要找到访问区间在查询区间内,就可以直接返回这段区间的值,不需要继续递归下去。
②:
{
这是个需要介绍的东西 称为Lazy标记。这是个很重要的东西,线段树的核心之一。
此处需要开一个add[node]数组,表示下标为node的节点需要加上add[node]的Lazy标记。这样就可以完成下放标记的任务。
code:
void down(int l,int r,int node){ if(add[node]!=0)//KC { add[node*2]+=add[node];//向左子树下放标记 add[node*2+1]+=add[node]; seg[node*2]+=add[node]*l;//④ seg[node*2+1]+=add[node]*r; add[node]=0; } return ;}
④:此处的l为上query函数的mid-l+1,为node节点的左子树的区间长度。之所以把 node左子树+Lazy标记*左子树区间长度 是因为每一个叶节点都需要加上此节点的Lazy标记。r处同上。
}
③:这需要解决的是为什么ql≤mid就可以直接ans+=query(node*2)。这主要是因为我们接下去寻找的是当前L~Mid区间里的在查询范围内的节点,因为ql≤mid无非就两种情况,l<ql或l≥ql且r在此情况下都大于等于ql,又因为每次return回来的一定是查询区间范围内的值,所以只要ql≤mid就可以了。qr>mid同上。
下面是区间修改;
//v为区间内修改(增加或减少)的值
code:
void change(int l,int r,int ql,int qr,int node,int v){ if(l>=ql&&r<=qr) { seg[node]+=v*(r-l+1);//① add[node]+=v;//① return ; } else { int mid=(l+r)>>1; down(mid-l+1,r-mid,node); if(ql<=mid)change(l,mid,ql,qr,node*2,v); if(qr>mid) change(mid+1,r,ql,qr,node*2+1,v); up(node);//② }}
①:如果访问区间已经在修改区间内,就可以直接修改node节点的值,并在node节点处留下标记,等着下一次询问或修改的时候做下放标记的操作。r-l+1为访问区间的长度。
②:因为此处为修改操作,需要进行up函数来更新。
0 0
- 线段树初步__ZERO__.
- 线段树初步理解...
- 初步线段树 hdu1166
- 线段树初步
- 线段树初步
- 线段树_初步
- hdu 1166 线段树 (初步)
- 线段树 初步:hdu 1166
- hdu 1166 敌兵布阵 (线段树初步)
- C++线段树初步(上)
- C++线段树初步(下)
- 线段树初步应用(一段一段的更新) HDOJ - 1698
- hdu 1754 I Hate It 线段树 初步
- HDU 1754 I Hate It(线段树初步应用)
- 敌兵布阵 线段树初步练习【MB-单点更新线段树】
- HDU 1166 敌兵布阵(线段树的初步应用2)
- uva 12299 RMQ with Shifts(线段树单点更新初步应用)
- 树套树:二维线段树初步:hdu1823——Luck and Love(单点修改,区间查询)
- Oracle 12c常用命令集合
- HttpClient
- MySql存储过程遇到的问题
- 对于嵌入式学习的见解及专业术语的理解
- Linux系统unzip解压后中文名乱码解决方法
- 线段树初步__ZERO__.
- Android保存图片到系统图库
- 归并排序(Merge Sort)递归、非递归 Java实现
- Web服务器使用JSP来创建网页的步骤
- JavaScript---BOM模型之window对象,DOM模型的节点获取
- CCTC 2017开幕在即,全部讲师和议程公布
- Redis作为缓存自我总结
- 推荐系统概述4
- 多版本通讯录