Segment Tree介绍与使用
来源:互联网 发布:网络版点歌软件 编辑:程序博客网 时间:2024/06/07 02:34
首先,看如下事例:
假设有数组 A[0..n-1],我们可以进行如下操作:
(1)求范围[ l, r ]间元素之和。0<=l<=r<=n-1;记为 Query 操作;
(2)更新某位置 i 处值,A[i] = new_val, 0<=i<=n-1;记为 Update 操作;
简单直观方法,就是遍历数组,可知此时(1)时间复杂度O(n),(2)时间复杂度O(1)。这种方法对于多更新操作的有利。
另一方法,创建新数组B,其中B[i]=SUM(A[0]..A[i]),0<=i<=n-1。此时(1)时间复杂度O(1),(2)时间复杂度O(n)。这种方法对于多查询操作的有利。
那么当两类操作差不多的情况下。有没有好的方法的呢?这里就引出了Segment Tree 的数据结构,通过使用它,我们可以将两类操作的时间复杂度都控制在O(lgn)。
Segment Tree 的表示描述如下:
1.叶节点中存储了数组中元素。
2.中间节点中存储了表述部分叶节点 Merge 后节点,不同使用场景下,Merge含义不同。上例中,Merge的含义就是叶节点求和。
Segment Tree 数据结构的实现,通常以数组方式来组织表示,对于下标为 i 的节点,其左孩子下标为 2*i +1,右孩子下标为 2*i +2。父节点的下标为 。
例子:数组 { 1,3, 5, 7, 9, 11 },更新位置值和查询任意区间和。建立 Segment Tree 如下,
如何针对给定数组建立 Segment Tree?
对于数组段 arr[0...n-1],每次我们将当前段分为二等分。递归地进行下去,直到当前段长度为1,处理每段时我们在相应节点存储和值。
建立Segment Tree每层(除了叶节点层)都是满的,也就是该树可以看着是完全二叉树(完全二叉树 + n个叶节点),所以Segment
Tree总节点数目为 2*n + 1。(n个叶节点+ n-1个中间节点)。树的高度为 。由于以数组来表示树结构,需要开辟的数组的大小为
。
查询给定范围的和?
树建立后,可以使用如下算法来获取范围和。
int getSum( node, l, r)
{
if range of node is within l and r
return value in node
else if range of node is completely outside l and r
return 0
else
return getSum(node's left child, l ,r ) + getSum(node's right child, l , r)
}
如何更新值?
同建树算法,和查询算法一样,递归的更新。对于给定要更新值的下标 i,令 diff = new_val - old_val。从根节点开始,对于所有 i 在节点的 range of node。
node值加diff。不在节点代表range中, 不进行更新。
void upDate(node , i, diff)
{
if i within range of node
node.value = node.value + diff;
upDate( node's left child, i, diff );
upDate( node's right child, i, diff );
}
实现代码如下:
int getMid(int s, int e) { returns + (e -s)/2; }int constructSTUtil(int arr[], int ss, int se, int* st, int si){ if(ss == se) { st[si] = arr[ss]; returnarr[ss]; } intmid = getMid(ss, se); st[si] = constructSTUtil(arr, ss, mid, st, si*2+1) + constructSTUtil(arr, mid+1, se, st, si*2+2); returnst[si];} int* constructST(int arr[], int n){ int x = (int)(ceil(log2(n)));//Height of segment tree int max_size = 2*(int)pow(2, x) - 1; //Maximum size of segment tree int* st = new int[max_size]; constructSTUtil(arr, 0, n-1, st, 0); return st;} int getSumUtil(int* st, int ss, int se, int qs, int qe, int index){ if(qs <= ss && qe >= se) return st[index]; if(se < qs || ss > qe) return 0; int mid = getMid(ss, se); return getSumUtil(st, ss, mid, qs, qe, 2*index+1) + getSumUtil(st, mid+1, se, qs, qe, 2*index+2);} void updateValueUtil(int* st, int ss, int se, int i, int diff, int index){ if(i < ss || i > se) return; st[index] = st[index] + diff; if(se != ss) { int mid = getMid(ss, se); updateValueUtil(st, ss, mid, i, diff, 2*index + 1); updateValueUtil(st, mid+1, se, i, diff, 2*index + 2); }} void updateValue(int arr[], int* st, int n, int i, int new_val){ if(i < 0 || i > n-1) { printf("Invalid Input"); return; } int diff = new_val - arr[i]; arr[i] = new_val; updateValueUtil(st, 0, n-1, i, diff, 0);} int getSum(int* st, int n, int qs, int qe){ if(qs < 0 || qe > n-1 || qs > qe) { printf("Invalid Input"); return-1; } return getSumUtil(st, 0, n-1, qs, qe, 0);}
- Segment Tree介绍与使用
- Segment tree
- Segment Tree
- Segment Tree
- segment Tree
- Segment Tree
- Segment Tree
- 线段树(segment tree)
- 线段树(segment tree)
- 线段树(segment tree)
- Segment Tree Template
- 线段树(segment tree)
- Segment Tree with Lazy
- Segment Tree 扫描线
- RMQ_Sparse Table & Segment Tree
- 线段树(segment tree)
- Lintcode - Segment Tree Build
- Lintcode - Segment Tree Query
- Button cannot be resolved to a type 解决方法
- java中重载与重写的区别
- tomcat启动增加内存
- VBS 下载指定URL地址EXE文件并运行命令:
- WM_QUIT WM_CLOSE WM_DESTROY消息的区别
- Segment Tree介绍与使用
- svn被锁住的解决方式
- java适配器模式
- 主板 术语信息
- Linux--4:Linux文件系统
- scilab文件执行
- Silverlight中文件的生成操作与其对应的获取方法
- HTML 中 id name class 区别
- 关于高斯模糊的详细介绍及python代码实现