脱离ACM队伍已经一年多了,现在还能手写的算法不多,线段树是其中一种。谨以此文纪念逝去的ACM生涯
线段树是一种二叉搜索树,常用于区间求和、区间求极值,其查询和更新时间复杂度是O(logN)。
线段树的主要操作包括初始化、更新和查询
1.初始化
初始化过程是一个递归算法,从根节点递归全树。作用是设定子节点区间范围、区间和、子节点索引以及父节点的左右子节点索引
2.查询
查询过程是一个递归算法,从根节点递归全树。首先初始化全局变量res值为0,用以保存结果,然后寻找最浅的被查询区间包含的节点。若节点左右边界均不在查询区间内,直接return;若节点左右边界均在查询区间内,该节点区间值与res相加,return;否则继续递归节点。
3.更新
更新过程与查询比较类似,这里不再赘述,其区别是更新会递归到最深的子节点,而不是查询那样浅尝辄止
话不多说,还是上代码吧
class LineTree {
private nodes;
private sum;
private res;
constructor(arr: number[]) {
var res = 0;
this.sum = [];
this.nodes = [];
var n = arr.length;
for(var i=0 ;i<n; i++) {
res += arr[i];
this.sum[i] = res;
}
var node = {
'left' : 0,
'right' : n - 1,
'value' : res,
'index' : 0,
'lindex' : null,
'rindex' : null
};
this.nodes.push( node );
this.build(node);
}
private build(node) {
if(node.left == node.right) {
return;
}
var left = node.left;
var right = Math.floor( (node.left + node.right) / 2 );
var left_node = {
'left' : left,
'right' : right,
'value' : left == 0 ? this.sum[right] : this.sum[right] - this.sum[left-1],
'index' : this.nodes.length,
'lindex' : null,
'rindex' : null
};
this.nodes[node.index].lindex = left_node.index;
left = Math.floor( (node.left + node.right) / 2 ) + 1;
right = node.right;
var right_node = {
'left' : left,
'right' : right,
'value' : left == 0 ? this.sum[right] : this.sum[right] - this.sum[left-1],
'index' : this.nodes.length + 1,
'lindex' : null,
'rindex' : null
};
this.nodes[node.index].rindex = right_node.index;
this.nodes.push(left_node, right_node);
this.build(left_node);
this.build(right_node);
}
private callQuery(node, left, right) {
if(node.left > right || node.right < left) {
return;
}
else if(left <= node.left && right >= node.right) {
this.res += node.value;
return;
}
else {
this.callQuery( this.nodes[node.lindex], left, right );
this.callQuery( this.nodes[node.rindex], left, right );
}
}
public query(left: number, right: number): number {
this.res = 0;
this.callQuery(this.nodes[0], left, right);
return this.res;
}
private callUpdate(node, index, value) {
if(node.left > index || node.right < index) {
return;
}
else {
this.nodes[node.index].value += value;
if(node.left == node.right) {
return;
}
else {
this.callUpdate(this.nodes[node.lindex], index, value);
this.callUpdate(this.nodes[node.rindex], index, value);
}
}
}
public update(index: number, value: number): void {
this.callUpdate(this.nodes[0], index, value);
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。