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();
}
}
}