コード例 #1
0
    // 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));
    }
コード例 #2
0
    // 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));
    }
コード例 #3
0
        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));
                    }
                }
            }
        }
コード例 #4
0
        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));
                    }
                }
            }
        }
コード例 #5
0
    // 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;
            }
        }
    }
コード例 #6
0
ファイル: GSS1.cs プロジェクト: Dariasz/SPOJ
 public int Query(int queryStartIndex, int queryEndIndex)
 => _segmentTree.Query(queryStartIndex, queryEndIndex).MaximumSum;
コード例 #7
0
 public int Query(int queryStartIndex, int queryEndIndex)
 => _segmentTree.Query(queryStartIndex, queryEndIndex).MostFrequentValueCount;
コード例 #8
0
ファイル: RPLN.cs プロジェクト: Dariasz/SPOJ
 public int Solve(int queryStartIndex, int queryEndIndex)
 => _segmentTree.Query(queryStartIndex, queryEndIndex);
コード例 #9
0
ファイル: BRCKTS.cs プロジェクト: Dariasz/SPOJ
 public bool IsBalanced()
 => _segmentTree.Query(0, _brackets.Length - 1);