集训日志(一)线段树
来源:互联网 发布:银行业大数据精准营销 编辑:程序博客网 时间:2024/05/17 01:40
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。
使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。
线段树是建立在线段的基础上,每个结点都代表了一条线段[a,b]。长度为1的线段称为元线段。非元线段都有两个子结点,左结点代表的线段为[a,(a + b) / 2],右结点代表的线段为[((a + b) / 2)+1,b]。
下图就是一棵长度范围为[1,9]的线段树。
长度范围为[1,L] 的一棵线段树的深度为log (L) + 1。这个显然,而且存储一棵线段树的空间复杂度为O(L)。
线段树支持最基本的操作为插入和删除一条线段。下面以插入为例,详细叙述,删除类似。
将一条线段[a,b] 插入到代表线段[l,r]的结点p中,如果p不是元线段,那么令mid=(l+r)/2。如果b<mid,那么将线段[a,b] 也插入到p的左儿子结点中,如果a>mid,那么将线段[a,b] 也插入到p的右儿子结点中。
插入(删除)操作的时间复杂度为O(logn)。
线段树的特征:
1、线段树的深度不超过log2(n)+1 (n是根节点对应区间的长度)。
2、线段树上,任意一个区间被分解后得等到终止节点数目都是log(n)量级。
线段树上更新叶子节点和进行区间分解时间复杂度都是O(log(n))的,这些特点为线段树在较短时间内完成插入数据,更新数据,查找,统计等工作提供了理论依据。
做线段树题,至少支持下列操作:
1、bulid 新建一棵线段树
2、insert 将包含在某个区间内的元素全部插入树中
3、query 查询某个区间内的值,如果有变动就记录在全局变量里。
关键点:用线段树解题时,一定要想清楚每个节点要存哪些信息,以及这些信息如何高效更新,维护,查询。不要一更新就涉及到叶子节点,那样更新效率最坏就变成O(n)的了。
例题:POJ 3264 Balanced Lineup
给定Q(1<=Q<=200,000)个数AQ,多次求任意区间内Ai-Aj中最大数和最小数的差。
Sample input:
6 3 (6个数,3次查询)
1
7
3
4
2
5
1 5
4 6
2 2
Sample Output:
6
3
0
先写节点:
struct Cnode
{
int L,R; //区间起点和终点
int minV,maxV; //本区间里的最大最小值
Cnode *pleft .*pright;
}
一般在写节点时,可以使用左右节点指针,也可以换成一个数组root存放线段树。根节点下标为0,假设线段树上某节点下表为i,则:
左子节点下标为i*2+1,右子节点下标为 i*2+2,
如果用一位数组存放线段树,而且根节点区间为[1,n],一般数组需要用4n个元素(直接记住)。
#include <iostream>#include <cstdio>using namespace std;const int INF=0xffffff;int minV=INF;int maxV=-INF;struct node{int L,R;int minV,maxV;int mid(){return (L+R)/2;}}tree[1600010];void build(int root,int L,int R){ tree[root].L=L; tree[root].R=R; tree[root].minV=INF; tree[root].maxV=-INF; if(L!=R) { build(2*root,L,(L+R)/2); build(2*root+1,(L+R)/2+1,R); }}void insert (int root,int i,int v)//将第i个数,其值为v,插入线段树{ if (tree[root].L==tree[root].R) { tree[root].minV=v; tree[root].maxV=v; return ; } tree[root].minV=min(tree[root].minV,v); tree[root].maxV=max(tree[root].maxV,v); if(i<=tree[root].mid()) insert(root*2,i,v); else insert(root*2+1,i,v);}void query(int root,int s,int e)//查询区间[s,e]中的最小值和最大值,如果更优就记在全局变量里{ if(tree[root].minV>=minV && tree[root].maxV<=maxV) return ; if(tree[root].L==s && tree[root].R==e) { maxV=max(tree[root].maxV,maxV); minV=min(tree[root].minV,minV); return; } if (e<=tree[root].mid()) query(root*2,s,e); else if (s>tree[root].mid()) query(root*2+1,s,e); else { query(root*2,s,tree[root].mid()); query(root*2+1,tree[root].mid()+1,e); }}int main(){ int N,T,h; cin>>N>>T; build(1,1,N); for (int i=1;i<=N;i++) { cin>>h; insert(1,i,h); } for (int i=1;i<=T;i++) { int s,e; cin>>s>>e; minV=INF; maxV=-INF; query(1,s,e); cout<<maxV-minV<<endl; } return 0;}
0 0
- 集训日志(一)线段树
- 【集训】Tire & 线段树
- 【集训】DP & 搜索 & 线段树
- CSU 1082: 憧憬一下集训 (线段树 扫描线)
- 【SDOI省队集训题】pair(线段树+二分)
- 2017暑假集训 div1 线段树(1)
- 2017暑假集训 div1 线段树(2)
- 线段树(一)
- 线段树(一)
- 线段树 csu1082 憧憬一下集训
- 【集训】DP & 搜索 & 线段树 Day 2
- 算法集训(一)水题
- loj #6062. 「2017 山东一轮集训 Day2」Pair(线段树)
- 线段树学习(一)
- 线段树学习(一)
- 线段树(一)HDU1166
- 数据结构-----线段树(一)
- 线段树入门(一)
- 原来C++里边只要是非零都认为是真,只有在值为0的时候才认为是假
- Maven系列--pom.xml 配置详解
- coj1224(宽度优先搜索)
- 产品第一要务
- java(JSP)中几种获取项目路径方式
- 集训日志(一)线段树
- 在Linux下,一个文件也有三种时间,分别是:访问时间、修改时间、状态改动时间
- HDU 2845 Beans DP
- 两种线程:Runable与Thread区别详解
- 【VC6.0】直线的橡皮筋绘图技术
- nc抓包改包上传
- windows7自动关机命令
- bitmap的用法(浅谈)
- Unable to execute dex: Multiple dex files define