namespace CodeJam.Sample.DataStructures { using System; using System.Collections.Generic; using System.Linq; /// /// Implement the Binary Indexed Tree data structure. /// Simulation of an array of N elements for which the operation of incrementing x[i] by j /// and the operation give x[1]+...+x[i] are both O(log N). /// public class BinaryIndexedTree { /// /// The number of elements in the array we are simulating. /// private int numberOfElements; /// /// The contents of the internal array. /// private int[] contents; /// /// Initializes a new instance of the class. /// /// Number of elements in the array. public BinaryIndexedTree(int n) { this.numberOfElements = n; this.contents = new int[n + 1]; } /// /// Gets or sets the element at the specified index in the array. /// /// The element at the index. /// 1-Based Index at which to get or set. public int this[int index] { get { return this.Accumulate(index) - this.Accumulate(index - 1); } set { this.Increment(index, value - this[index]); } } /// /// Increment an element of the simulated array by a certain amount. /// /// 1-Based index of simulated array. /// Amount by which to increment. public void Increment(int index, int amount) { while (index <= this.numberOfElements) { this.contents[index] += amount; index += this.LeastSignificantBit(index); } } /// /// Return the sum of all of the elements in the array up to and including the given index /// /// The sum of all elements up to the given index /// 1-Based index up to which to accumulate. public int Accumulate(int index) { int accumulation = 0; while (index > 0) { accumulation += this.contents[index]; index -= this.LeastSignificantBit(index); } return accumulation; } /// /// Returns the least significant bit of an integer. /// /// The least significant bit. /// Input integer. private int LeastSignificantBit(int n) { return n & (-n); } } /// /// A test class for running on ideone /// public class Test { /// /// Solve the problem, using the Binary Indexed Tree data structure. /// public static void Main() { int numberOfCases = GetInt(); for (int caseIndex = 1; caseIndex <= numberOfCases; ++caseIndex) { var parameters = GetInts(); int numberOfStudents = parameters[0]; int numberOfChocolates = parameters[1]; /* We are going to use a BinaryIndexedTree to simulate an array x[1], ..., x[N] * where student i has x[1]+...+x[i] chocolates. * * Then we can find out how many chocolates student i has by calling Accumulate(i) (O(log N) time) * and we can give K chocolates to students i, i+1, ..., j by calling: * Increment(i, K) * Increment(j+1, -K) * * Note our BinaryIndexedTree uses 1-indexed indices, and the problem uses 0-indexed indices, so we will have to * add 1 to the student indices we get. */ var bit = new BinaryIndexedTree(numberOfStudents); for (int chocolateIndex = 0; chocolateIndex < numberOfChocolates; ++chocolateIndex) { parameters = GetInts(); int fromStudent = parameters[0]; int toStudent = parameters[1]; int chocolateGift = parameters[2]; bit.Increment(fromStudent + 1, chocolateGift); bit.Increment(toStudent + 2, -chocolateGift); } int numberOfFriends = GetInt(); for (int friendIndex = 0; friendIndex < numberOfFriends; ++friendIndex) { int friendLocation = GetInt(); Console.WriteLine(bit.Accumulate(friendLocation + 1)); } } } /// /// Read a single integer from stdin /// /// The read integer. private static int GetInt() { return int.Parse(Console.ReadLine()); } /// /// Read a line of space separated integers from stdin /// /// The read integers. private static List GetInts() { return Console.ReadLine().Split(' ').Select(_ => int.Parse(_)).ToList(); } } }