public void Update(IncrementQueryObject updatedLeftChild, IncrementQueryObject updatedRightChild) { // Zero these out first as we want the total of the children's updated contributions. _remainder0CountWithoutRangeIncrements = _remainder1CountWithoutRangeIncrements = _remainder2CountWithoutRangeIncrements = 0; SubsumeRemainders(updatedLeftChild); SubsumeRemainders(updatedRightChild); }
public IncrementQueryObject Combine(IncrementQueryObject rightAdjacentObject) { var combinedQueryObject = new IncrementQueryObject(); combinedQueryObject.SubsumeRemainders(this); combinedQueryObject.SubsumeRemainders(rightAdjacentObject); return(combinedQueryObject); }
// Instead of returning the children object directly, we have to add on the parent's range addition. The // children query object knows the subset of the parent segment it intersects with, and everything in // there needs the additions that were applied to the parent segment as a whole. It's kind of weird, any // pending range additions specifically for the children object gets brought out and added to the sum when // we do .Combine or .Sum, but recursively it makes sense: the children object has a sum but still needs // to know about the parent's range additions. public IncrementQueryObject Query( int treeArrayIndex, int segmentStartIndex, int segmentEndIndex, int queryStartIndex, int queryEndIndex) { var parentQueryObject = _treeArray[treeArrayIndex]; if (queryStartIndex <= segmentStartIndex && queryEndIndex >= segmentEndIndex) { return(parentQueryObject); } int leftChildTreeArrayIndex = (treeArrayIndex << 1) | 1; int rightChildTreeArrayIndex = leftChildTreeArrayIndex + 1; int leftChildSegmentEndIndex = (segmentStartIndex + segmentEndIndex) >> 1; IncrementQueryObject childrenQueryObject; if (queryStartIndex <= leftChildSegmentEndIndex && queryEndIndex > leftChildSegmentEndIndex) { childrenQueryObject = Query( leftChildTreeArrayIndex, segmentStartIndex, leftChildSegmentEndIndex, queryStartIndex, queryEndIndex) .Combine(Query( rightChildTreeArrayIndex, leftChildSegmentEndIndex + 1, segmentEndIndex, queryStartIndex, queryEndIndex)); } else if (queryStartIndex <= leftChildSegmentEndIndex) { childrenQueryObject = Query( leftChildTreeArrayIndex, segmentStartIndex, leftChildSegmentEndIndex, queryStartIndex, queryEndIndex); } else { childrenQueryObject = Query( rightChildTreeArrayIndex, leftChildSegmentEndIndex + 1, segmentEndIndex, queryStartIndex, queryEndIndex); } var queryObject = new IncrementQueryObject { RangeIncrements = parentQueryObject.RangeIncrements }; queryObject.SubsumeRemainders(childrenQueryObject); return(queryObject); }
private void Build(int treeArrayIndex, int segmentStartIndex, int segmentEndIndex) { if (segmentStartIndex == segmentEndIndex) { _treeArray[treeArrayIndex] = new IncrementQueryObject { Remainder0Count = 1 }; return; } int leftChildTreeArrayIndex = (treeArrayIndex << 1) | 1; int rightChildTreeArrayIndex = leftChildTreeArrayIndex + 1; int leftChildSegmentEndIndex = (segmentStartIndex + segmentEndIndex) >> 1; Build(leftChildTreeArrayIndex, segmentStartIndex, leftChildSegmentEndIndex); Build(rightChildTreeArrayIndex, leftChildSegmentEndIndex + 1, segmentEndIndex); _treeArray[treeArrayIndex] = _treeArray[leftChildTreeArrayIndex].Combine(_treeArray[rightChildTreeArrayIndex]); }
public void SubsumeRemainders(IncrementQueryObject child) { switch (child.RangeIncrements % 3) { case 0: _remainder0CountWithoutRangeIncrements += child._remainder0CountWithoutRangeIncrements; _remainder1CountWithoutRangeIncrements += child._remainder1CountWithoutRangeIncrements; _remainder2CountWithoutRangeIncrements += child._remainder2CountWithoutRangeIncrements; break; case 1: _remainder0CountWithoutRangeIncrements += child._remainder2CountWithoutRangeIncrements; _remainder1CountWithoutRangeIncrements += child._remainder0CountWithoutRangeIncrements; _remainder2CountWithoutRangeIncrements += child._remainder1CountWithoutRangeIncrements; break; case 2: _remainder0CountWithoutRangeIncrements += child._remainder1CountWithoutRangeIncrements; _remainder1CountWithoutRangeIncrements += child._remainder2CountWithoutRangeIncrements; _remainder2CountWithoutRangeIncrements += child._remainder0CountWithoutRangeIncrements; break; } }