/// <summary> /// Checks all properties of the specified tree for correctness. /// </summary> /// <typeparam name="TKey">Type of keys.</typeparam> /// <typeparam name="TValue">Type of values.</typeparam> /// <param name="tree">Specified tree.</param> /// <param name="elements">Expected elements in the tree.</param> /// <param name="isMulti">True if testing the multi-dictionary scenario.</param> private static void CheckTree <TKey, TValue>(LeftLeaningRedBlackTree <TKey, TValue> tree, List <KeyValuePair <TKey, TValue> > elements, bool isMulti) where TKey : IComparable { // Check count and keys Assert.AreEqual(elements.Count, tree.Count); List <TKey> sortedKeys = elements.Select(e => e.Key).Distinct().OrderBy(k => k).ToList(); List <TKey> binaryTreeKeys = tree.GetKeys().ToList(); Assert.AreEqual(sortedKeys.Count, binaryTreeKeys.Count); // Check key values for (int i = 0; i < sortedKeys.Count; i++) { Assert.AreEqual(sortedKeys[i], binaryTreeKeys[i]); List <TValue> sortedKeyValues = elements.Where(e => 0 == e.Key.CompareTo(sortedKeys[i])).Select(e => e.Value).OrderBy(v => v).ToList(); List <TValue> binaryTreeKeyValues = tree.GetValuesForKey(sortedKeys[i]).ToList(); Assert.AreEqual(sortedKeyValues.Count, binaryTreeKeyValues.Count); for (int j = 0; j < sortedKeyValues.Count; j++) { Assert.AreEqual(sortedKeyValues[j], binaryTreeKeyValues[j]); } if (!isMulti) { Assert.AreEqual(tree.GetValueForKey(sortedKeys[i]), binaryTreeKeyValues.Single()); } } // Check values List <TValue> sortedValues = sortedKeys.SelectMany(k => elements.Where(e => 0 == e.Key.CompareTo(k)).Select(e => e.Value).OrderBy(v => v)).ToList(); List <TValue> binaryTreeValues = tree.GetValuesForAllKeys().ToList(); Assert.AreEqual(sortedValues.Count, binaryTreeValues.Count); for (int i = 0; i < sortedValues.Count; i++) { Assert.AreEqual(sortedValues[i], binaryTreeValues[i]); } // Check additional properties if (0 < elements.Count) { Assert.AreEqual(sortedKeys[0], tree.MinimumKey); Assert.AreEqual(sortedKeys[sortedKeys.Count - 1], tree.MaximumKey); Assert.AreEqual(sortedValues[0], tree.MinimumValue); Assert.AreEqual(sortedValues[sortedValues.Count - 1], tree.MaximumValue); } }
public static ulong Solve(int n, int[][] edges, ulong[] coins) { if (n == 1) { return(ulong.MaxValue); } var adj = ToDirectedTree(edges, n + 1); var head = edges[0][0]; var sumsBelow = new ulong[n + 1]; var stack = new Stack <int>(n + 1); var ignoreSums = new bool[n + 1]; foreach (var node in Traverse_Tree_PostOrder_NonRec(head, v => adj[v])) { sumsBelow[node] = coins[node - 1] + adj[node].Select(v => sumsBelow[v]).Sum(); } var total = sumsBelow[head]; var sumsSet = new LeftLeaningRedBlackTree <ulong, int>((x, y) => x.CompareTo(y), (x, y) => x.CompareTo(y)); for (var i = 1; i <= n; i++) { sumsSet.Add(sumsBelow[i], i); } var best = ulong.MaxValue; var path = new List <int>(n + 1) { head }; var notInA = new bool[n + 1]; notInA[head] = true; foreach (var edgeInfo in Traverse_Dfs_WithEvents(head, v => adj[v])) { var aNode = edgeInfo.Child; if (edgeInfo.IsDownNotUp) { path.Add(aNode); notInA[edgeInfo.Parent] = true; foreach (var otherChild in adj[edgeInfo.Parent]) { if (otherChild != edgeInfo.Child) { foreach (var node in Traverse_Tree_Dfs(otherChild, v => adj[v], stack)) { notInA[node] = true; } } } } else { path.RemoveAt(path.Count - 1); notInA[edgeInfo.Parent] = false; foreach (var otherChild in adj[edgeInfo.Parent]) { if (otherChild != edgeInfo.Child) { foreach (var node in Traverse_Tree_Dfs(otherChild, v => adj[v], stack)) { notInA[node] = false; } } } continue; } var a = sumsBelow[aNode]; if (a == total - a) { best = Math.Min(best, a); } foreach (var pathNode in path) { if (pathNode != aNode) { var sum = sumsBelow[pathNode]; sumsSet.Remove(sum, pathNode); sumsSet.Add(sum - a, pathNode); } } var searchme = new List <ulong>(3) { a }; if (total > 2 * a) { searchme.Add(total - 2 * a); } if (total != a && (total - a) % 2 == 0) { searchme.Add((total - a) / 2); } foreach (var sum in searchme) { if (sumsSet.GetValuesForKey(sum).Any(i => notInA[i])) { best = CalcBest(best, a, sum, total - a - sum); } } foreach (var pathNode in path) { if (pathNode != aNode) { var sum = sumsBelow[pathNode]; sumsSet.Remove(sum - a, pathNode); sumsSet.Add(sum, pathNode); } } } return(best); }