活跃农民
- 积分
- 509
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2013-6-5
- 最后登录
- 1970-1-1
|
0418 1. Range Sum Query 2D - Mutable
TLE ------
// first of f***ing all, we need a segment tree implementation
class SegmentTree {
constructor (array, merge) {
this.nodes = []
this.merge = merge
this.endIndex = array.length - 1
this.buildTree(0, 0, array.length - 1, array)
}
buildTree (nodeIndex, nodeStart, nodeEnd, array) {
if (nodeStart > nodeEnd) { // !!! this check
return
}
if (nodeStart === nodeEnd) {
this.nodes[nodeIndex] = array[nodeStart]
} else {
const nodeMid = nodeStart + Math.trunc((nodeEnd - nodeStart) / 2)
this.buildTree(2 * nodeIndex + 1, nodeStart, nodeMid, array)
this.buildTree(2 * nodeIndex + 2, nodeMid + 1, nodeEnd, array)
// merge IMPORTANT
this.nodes[nodeIndex] = this.merge(this.nodes[2 * nodeIndex + 1], this.nodes[2 * nodeIndex + 2])
}
}
query (start, end) {
// do some check we ignore
return this.doQuery(0, 0, this.endIndex, start, end)
}
doQuery (nodeIndex, nodeStart, nodeEnd, start, end) {
if (nodeStart === nodeEnd && start === end && nodeStart === start) {
return this.nodes[nodeIndex]
} else {
const nodeMid = nodeStart + Math.trunc((nodeEnd - nodeStart) / 2)
if (end <= nodeMid) {
return this.doQuery(2 * nodeIndex + 1, nodeStart, nodeMid, start, end)
} else if (start >= nodeMid + 1) {
return this.doQuery(2 * nodeIndex + 2, nodeMid + 1, nodeEnd, start, end)
} else {
const left = this.doQuery(2 * nodeIndex + 1, nodeStart, nodeMid, start, nodeMid)
const right = this.doQuery(2 * nodeIndex + 2, nodeMid + 1, nodeEnd, nodeMid + 1, end)
return this.merge(left, right)
}
}
}
doUpdate (nodeIndex, nodeStart, nodeEnd, index, val) {
if (nodeStart === nodeEnd && nodeStart === index) {
this.nodes[nodeIndex] = val
} else {
const nodeMid = nodeStart + Math.trunc((nodeEnd - nodeStart) / 2)
if (index <= nodeMid) {
this.doUpdate(2 * nodeIndex + 1, nodeStart, nodeMid, index, val)
} else {
this.doUpdate(2 * nodeIndex + 2, nodeMid + 1, nodeEnd, index, val)
}
// !!! IMPORTANT: merge
this.nodes[nodeIndex] = this.merge(this.nodes[2 * nodeIndex + 1], this.nodes[2 * nodeIndex + 2])
}
}
update (index, val) {
// check, we ignore
this.doUpdate(0, 0, this.endIndex, index, val)
}
toString () {
return 'why'
}
}
// const arr = [3, 1, 4, 1, 3, 2, 5, 4, 7]
// const seg = new SegmentTree(arr, (a, b) => a + b)
// seg.update(3, 8)
/**
* @param {number[][]} matrix
*/
var NumMatrix = function(matrix = []) {
if (matrix.length === 0 || matrix[0].length === 0) {
this.empty = true
return
}
// first, build the segment tree for each row
let rowTrees
this.rowTrees = rowTrees = matrix.map(row => new SegmentTree(row, (a, b) => a + b))
// now, build the tree of trees
this.tree = new SegmentTree(rowTrees, (tree1, tree2) => { // merge two trees
const newTree = new SegmentTree([], (a, b) => a + b)
newTree.endIndex = tree1.endIndex // !!!! otherwise wrong since you give empty to constructor
const merge = (nodeIndex) => {
if (tree1.nodes[nodeIndex] == null) {
return
}
newTree.nodes[nodeIndex] = tree1.nodes[nodeIndex] + tree2.nodes[nodeIndex]
merge(2 * nodeIndex + 1)
merge(2 * nodeIndex + 2)
}
merge(0)
return newTree
})
};
/**
* @param {number} row
* @param {number} col
* @param {number} val
* @return {void}
*/
NumMatrix.prototype.update = function(row, col, val) {
const rowTree = this.rowTrees[row]
rowTree.update(col, val)
this.tree.update(row, rowTree)
};
/**
* @param {number} row1
* @param {number} col1
* @param {number} row2
* @param {number} col2
* @return {number}
*/
NumMatrix.prototype.sumRegion = function(row1, col1, row2, col2) {
const tree = this.tree.query(row1, row2)
return tree.query(col1, col2)
};
TLE --- WHY?????
const matrix = [
[3, 0, 1, 4, 2],
[5, 6, 3, 2, 1],
[1, 2, 0, 1, 5],
[4, 1, 0, 1, 7],
[1, 0, 3, 0, 5]
]
const n = new NumMatrix(matrix)
console.log(n.sumRegion(2, 1, 4, 3) === 8)
n.update(3, 2, 2)
console.log(n.sumRegion(2, 1, 4, 3) === 10)
|
|