// Here's a good guide: https://www.geeksforgeeks.org/find-lca-in-binary-tree-using-rmq/. private Vertex GetLeastCommonAncestor(Vertex firstVertex, Vertex secondVertex) { int firstInitialIndex = firstVertex.EulerTourInitialIndex.Value; int secondInitialIndex = secondVertex.EulerTourInitialIndex.Value; return(firstInitialIndex < secondInitialIndex ? _eulerTourSegmentTree.Query(firstInitialIndex, secondInitialIndex) : _eulerTourSegmentTree.Query(secondInitialIndex, firstInitialIndex)); }
// Here's a good guide: https://www.geeksforgeeks.org/find-lca-in-binary-tree-using-rmq/. // First, we have to build a rooted tree. Then, we have to compute its Euler tour. I do // this using a stack but it's really easy using recursion, just a little less performant. // Then, convince yourself the LCA of two vertices is the vertex of minimum depth between // the first occurrences of those two vertices in the Euler tour. We can build a segment // tree on top of the Euler tour, with query objects storing the vertex of minimum depth // in a range. Then when asked to find the LCA of two vertices, query the segment tree for // the minimum depth vertex between the vertices' initial indices in the Euler tour. public int Solve(int firstVertexID, int secondVertexID) { int firstInitialIndex = _tree.Vertices[firstVertexID].EulerTourInitialIndex.Value; int secondInitialIndex = _tree.Vertices[secondVertexID].EulerTourInitialIndex.Value; return(firstInitialIndex < secondInitialIndex ? _segmentTree.Query(firstInitialIndex, secondInitialIndex) : _segmentTree.Query(secondInitialIndex, firstInitialIndex)); }
public void LazySumSegmentTree_ForRandomOperations() { var rand = new Random(); for (int a = 0; a < _sourceArrays.Length; ++a) { var sourceArray = _sourceArrays[a]; var lazySumSegmentTree = new LazySumSegmentTree(sourceArray); var arrayBasedSegmentTree = new ArrayBasedSegmentTree <SumQueryObject, int>(sourceArray); for (int r = 0; r < 1000; ++r) { int firstIndex = rand.Next(0, sourceArray.Length); int secondIndex = rand.Next(0, sourceArray.Length); int startIndex = Math.Min(firstIndex, secondIndex); int endIndex = Math.Max(firstIndex, secondIndex); int mode = rand.Next(2); if (mode == 0) { NaiveSegmentTreeAlternatives.Update(sourceArray, startIndex, endIndex, x => x + r); lazySumSegmentTree.Update(startIndex, endIndex, rangeAddition: r); arrayBasedSegmentTree.Update(startIndex, endIndex, x => x + r); } else { int expected = NaiveSegmentTreeAlternatives.SumQuery(sourceArray, startIndex, endIndex); Assert.AreEqual(expected, lazySumSegmentTree.SumQuery(startIndex, endIndex)); Assert.AreEqual(expected, arrayBasedSegmentTree.Query(startIndex, endIndex)); } } } }
private void VerifiesUpdates <TQueryObject>(Func <IReadOnlyList <int>, int, int, int> naiveVerifier) where TQueryObject : SegmentTreeQueryObject <TQueryObject, int>, new() { Func <int, int> updater = x => x + 1; for (int a = 0; a < _sourceArrays.Length; ++a) { var sourceArray = _sourceArrays[a]; var nodeBasedSegmentTree = new NodeBasedSegmentTree <TQueryObject, int>(sourceArray); var arrayBasedSegmentTree = new ArrayBasedSegmentTree <TQueryObject, int>(sourceArray); var nonRecursiveSegmentTree = new NonRecursiveSegmentTree <TQueryObject, int>(sourceArray); for (int i = 0; i < sourceArray.Length; ++i) { for (int j = i; j < sourceArray.Length; ++j) { NaiveSegmentTreeAlternatives.Update(sourceArray, i, j, updater); nodeBasedSegmentTree.Update(i, j, updater); arrayBasedSegmentTree.Update(i, j, updater); nonRecursiveSegmentTree.Update(i, j, updater); int expected = naiveVerifier(sourceArray, i, j); Assert.AreEqual(expected, nodeBasedSegmentTree.Query(i, j)); Assert.AreEqual(expected, arrayBasedSegmentTree.Query(i, j)); Assert.AreEqual(expected, nonRecursiveSegmentTree.Query(i, j)); } } } }
// Finds the edge of maximum weight on the path up the tree from the descendant vertex // to the ancestor vertex. The HLD segment tree allows for log(n) querying when vertices // are within the same HLD chain. Some chain hopping may be necessary, but as the links // above mention, there are no more than log(n) chains. private int?QueryUp(Vertex descendantVertex, Vertex ancestorVertex) { int?pathMaximumEdgeWeight = null; while (true) { if (descendantVertex.HLDChainIndex == ancestorVertex.HLDChainIndex) { if (descendantVertex == ancestorVertex) { return(pathMaximumEdgeWeight); // Could still be null if initial vertices were equal. } // Consider the following tree, rooted at V0: V0 --- V1 -- V2 -- V3. // Say we're querying from V3 (descendant) to V1 (ancestor). Along that path we need // to consider V3's edge to V2, and V2's edge to V1. In the HLD segment tree, vertices // correspond with the edge to their parent. So we need to query the range between the // descendant and one before the ancestor, V3 to V2. (The base array for the segment tree // has ancestors appearing before descendants, explaining the start & end indices below.) int chainMaximumEdgeWeight = _hldBaseArraySegmentTree.Query( ancestorVertex.HLDBaseArrayIndex.Value + 1, descendantVertex.HLDBaseArrayIndex.Value).Weight.Value; return(Math.Max(pathMaximumEdgeWeight ?? 0, chainMaximumEdgeWeight)); } else { var descendantChainHead = _tree.HLDChainHeads[descendantVertex.HLDChainIndex.Value]; // Query through the descendant's chain head, which considers all the edges from the // descendant to the chain head, plus the edge from the chain head to the next chain. int descendantChainMaximumEdgeWeight = _hldBaseArraySegmentTree.Query( descendantChainHead.HLDBaseArrayIndex.Value, descendantVertex.HLDBaseArrayIndex.Value).Weight.Value; pathMaximumEdgeWeight = Math.Max(pathMaximumEdgeWeight ?? 0, descendantChainMaximumEdgeWeight); // Advance to the bottom of the next chain. descendantVertex = descendantChainHead.Parent; } } }
public int Query(int queryStartIndex, int queryEndIndex) => _segmentTree.Query(queryStartIndex, queryEndIndex).MaximumSum;
public int Query(int queryStartIndex, int queryEndIndex) => _segmentTree.Query(queryStartIndex, queryEndIndex).MostFrequentValueCount;
public int Solve(int queryStartIndex, int queryEndIndex) => _segmentTree.Query(queryStartIndex, queryEndIndex);
public bool IsBalanced() => _segmentTree.Query(0, _brackets.Length - 1);