脱离ACM队伍已经一年多了,如今还能手写的算法很少,线段树是其中一种。谨以此文记念逝去的ACM生涯node
线段树是一种二叉搜索树,经常使用于区间求和、区间求极值,其查询和更新时间复杂度是O(logN)。算法
线段树的主要操做包括初始化、更新和查询ui
初始化过程是一个递归算法,从根节点递归全树。做用是设定子节点区间范围、区间和、子节点索引以及父节点的左右子节点索引this
查询过程是一个递归算法,从根节点递归全树。首先初始化全局变量res值为0,用以保存结果,而后寻找最浅的被查询区间包含的节点。若节点左右边界均不在查询区间内,直接return;若节点左右边界均在查询区间内,该节点区间值与res相加,return;不然继续递归节点。spa
更新过程与查询比较相似,这里再也不赘述,其区别是更新会递归到最深的子节点,而不是查询那样浅尝辄止code
话很少说,仍是上代码吧blog
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); } }