90 lines
2.1 KiB
C#
90 lines
2.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace AnotherReplayReader.Utils
|
|
{
|
|
public record TimeIndexedPrefixSums(List<TimeSpan> Times, List<int> PrefixSums)
|
|
{
|
|
public void Add(TimeSpan time, int value)
|
|
{
|
|
if (Times.Count > 0 && time < Times.Last())
|
|
{
|
|
throw new ArgumentException("Time must be added in non-decreasing order.");
|
|
}
|
|
Times.Add(time);
|
|
PrefixSums.Add((PrefixSums.LastOrDefault()) + value);
|
|
}
|
|
|
|
public int Query(TimeSpan start, TimeSpan end)
|
|
{
|
|
var times = Times;
|
|
var prefix = PrefixSums;
|
|
|
|
int startIndex = LowerBound(times, start);
|
|
int endIndex = UpperBound(times, end);
|
|
|
|
if (startIndex >= times.Count || endIndex < 0 || startIndex > endIndex)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int result = prefix[endIndex];
|
|
|
|
if (startIndex > 0)
|
|
{
|
|
result -= prefix[startIndex - 1];
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public int GetTotal()
|
|
{
|
|
return PrefixSums.LastOrDefault();
|
|
}
|
|
|
|
public static int LowerBound(List<TimeSpan> arr, TimeSpan target)
|
|
{
|
|
int left = 0, right = arr.Count;
|
|
|
|
while (left < right)
|
|
{
|
|
int mid = left + (right - left) / 2;
|
|
|
|
if (arr[mid] < target)
|
|
{
|
|
left = mid + 1;
|
|
}
|
|
else
|
|
{
|
|
right = mid;
|
|
}
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
public static int UpperBound(List<TimeSpan> arr, TimeSpan target)
|
|
{
|
|
int left = 0, right = arr.Count;
|
|
|
|
while (left < right)
|
|
{
|
|
int mid = left + (right - left) / 2;
|
|
|
|
if (arr[mid] <= target)
|
|
{
|
|
left = mid + 1;
|
|
}
|
|
else
|
|
{
|
|
right = mid;
|
|
}
|
|
}
|
|
|
|
return left - 1;
|
|
}
|
|
}
|
|
}
|