private RootedTreeNode[,] PreprocessLCA() { int N = RootedTreeNodes.Length, M = 0; while ((1 << M) < N) { M++; } var p = new RootedTreeNode[N, M]; for (int i = 0; i < N; i++) { p[i, 0] = RootedTreeNodes[i].Parent; } for (int j = 1; 1 << j < N; j++) { for (int i = 0; i < N; i++) { if (p[i, j - 1] != null) { p[i, j] = p[p[i, j - 1].Node.Index, j - 1]; } } } return(p); }
public RootedTreeNode GetLowestCommonAncestor(RootedTreeNode p, RootedTreeNode q) { if (lcaPreprocess == null) { lcaPreprocess = PreprocessLCA(); } if (p.Level < q.Level) { RootedTreeNode tmp = p; p = q; q = tmp; } int log; for (log = 1; 1 << log <= p.Level; log++) { ; } log--; for (int i = log; i >= 0; i--) { if (p.Level - (1 << i) >= q.Level) { p = lcaPreprocess[p.Node.Index, i]; } } if (p == q) { return(p); } for (int i = log; i >= 0; i--) { if (lcaPreprocess[p.Node.Index, i] != null && lcaPreprocess[p.Node.Index, i] != lcaPreprocess[q.Node.Index, i]) { p = lcaPreprocess[p.Node.Index, i]; q = lcaPreprocess[q.Node.Index, i]; } } return(p.Parent); }
private readonly RootedTreeNode[] topologicalOrder; // root = topologicalOrder[0] public RootedTree(Graph graph, Node root) { if (graph == null || root == null || root.Graph != graph || graph.Edges.Count != graph.Nodes.Count - 1) { throw new ArgumentException(); } var n = graph.Nodes.Count; RootedTreeNodes = new RootedTreeNode[n]; // Build up tree structure without using recursion and create a topological ordering var level = new int[n]; var order = new int[n]; var parent = new int[n]; level[root.Index] = 0; order[0] = root.Index; parent[root.Index] = -1; for (int i = 0, j = 1; i < n; i++) { if (i == j) { throw new ArgumentException(); } foreach (var node in graph.GetNode(order[i]).GetAdjacentNodes()) { var nodeIndex = node.Index; if (nodeIndex != root.Index && level[nodeIndex] == 0) { parent[nodeIndex] = order[i]; level[nodeIndex] = level[order[i]] + 1; order[j++] = nodeIndex; } } } topologicalOrder = new RootedTreeNode[n]; for (int i = n - 1; i >= 0; i--) { var nodeIndex = order[i]; topologicalOrder[i] = new RootedTreeNode(this, graph.GetNode(nodeIndex), parent[nodeIndex], level[nodeIndex]); } Root = topologicalOrder[0]; }
public void TestTreeLCA() { Random r = new Random(0); for (int i = 0; i < 10; i++) { int N = r.Next(30000, 40000); int[] perm = new int[N]; for (int j = 0; j < N; j++) { perm[j] = j; } for (int j = 0; j < N; j++) { int swap = j + r.Next(N - j); int tmp = perm[j]; perm[j] = perm[swap]; perm[swap] = tmp; } Graph g = new Graph(N); for (int j = 1; j < N; j++) { int a = r.Next(j); g.AddEdge(perm[a], perm[j]); } RootedTree tree = new RootedTree(g, g.GetNode(perm[0])); for (int j = 0; j < 100; j++) { int a = r.Next(N), b = r.Next(N); RootedTreeNode p = tree.GetNode(a), q = tree.GetNode(b); // Naive solution var pp = p; var qq = q; List <RootedTreeNode> ptrail = new List <RootedTreeNode>(), qtrail = new List <RootedTreeNode>(); while (pp != null) { ptrail.Add(pp); pp = pp.Parent; } while (qq != null) { qtrail.Add(qq); qq = qq.Parent; } ptrail.Reverse(); qtrail.Reverse(); int k = 0; while (k + 1 < ptrail.Count && k + 1 < qtrail.Count && ptrail[k + 1] == qtrail[k + 1]) { k++; } RootedTreeNode expected = ptrail[k]; RootedTreeNode lca = tree.GetLowestCommonAncestor(p, q); Assert.AreSame(expected, lca); } } }
internal void SetNode(RootedTreeNode treeNode) { RootedTreeNodes[treeNode.Node.Index] = treeNode; }