Ejemplo n.º 1
0
    private void RunHLD(Vertex vertex, bool startsNewChain)
    {
        if (startsNewChain)
        {
            _hldChainHeads.Add(vertex);
        }
        vertex.HLDChainIndex = _hldChainHeads.Count - 1;

        _hldBaseArray.Add(vertex);
        vertex.HLDBaseArrayIndex = _hldBaseArray.Count - 1;

        if (vertex.Children.Any())
        {
            var heaviestChild = vertex.Children[0];
            for (int i = 1; i < vertex.Children.Count; ++i)
            {
                if (vertex.Children[i].SubtreeSize > heaviestChild.SubtreeSize)
                {
                    heaviestChild = vertex.Children[i];
                }
            }

            RunHLD(heaviestChild, startsNewChain: false);

            for (int i = 0; i < vertex.Children.Count; ++i)
            {
                if (vertex.Children[i] != heaviestChild)
                {
                    RunHLD(vertex.Children[i], startsNewChain: true);
                }
            }
        }
    }
Ejemplo n.º 2
0
    public Vertex[] GetEulerTour()
    {
        // For all n - 1 edges, we take the edge down to its child and then, eventually, back up
        // to its parent. So each edge contributes 2 vertices to the tour, and we get the root
        // initially without using any edges, so that's 2*(n - 1) + 1 = 2n - 1 vertices.
        var eulerTour       = new Vertex[2 * VertexCount - 1];
        int eulerTourIndex  = -1;
        var verticesToVisit = new Stack <Vertex>();

        verticesToVisit.Push(Root);

        while (verticesToVisit.Count > 0)
        {
            var vertex = verticesToVisit.Peek();
            eulerTour[++eulerTourIndex] = vertex;

            // If the EulerTourInitialIndex is null, it's the first time we're visiting the vertex.
            if (!vertex.EulerTourInitialIndex.HasValue)
            {
                vertex.EulerTourInitialIndex = eulerTourIndex;
            }

            if (vertex.EulerTourChildCounter == vertex.Children.Count)
            {
                verticesToVisit.Pop();
            }
            else
            {
                verticesToVisit.Push(vertex.Children[vertex.EulerTourChildCounter++]);
            }
        }

        return(eulerTour);
    }
Ejemplo n.º 3
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));
    }
Ejemplo n.º 4
0
    private WeightedRootedTree(int vertexCount, int rootID)
    {
        var vertices = new Vertex[vertexCount];

        for (int id = 0; id < vertexCount; ++id)
        {
            vertices[id] = new Vertex(this, id);
        }

        Vertices = vertices;
        Root     = vertices[rootID];
    }
Ejemplo n.º 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;
            }
        }
    }