-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
SegmentTree.cs
103 lines (90 loc) · 3.75 KB
/
SegmentTree.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
using System;
namespace DataStructures.SegmentTrees;
/// <summary>
/// Goal: Data structure with which you can quickly perform queries on an array (i.e. sum of subarray)
/// and at the same time efficiently update an entry
/// or apply a distributive operation to a subarray.
/// Idea: Preprocessing special queries
/// Hint: The query operation HAS to be associative (in this example addition).
/// </summary>
public class SegmentTree
{
/// <summary>
/// Initializes a new instance of the <see cref="SegmentTree" /> class.
/// Runtime complexity: O(n) where n equals the array-length.
/// </summary>
/// <param name="arr">Array on which the queries should be made.</param>
public SegmentTree(int[] arr)
{
// Calculates next power of two
var pow = (int)Math.Pow(2, Math.Ceiling(Math.Log(arr.Length, 2)));
Tree = new int[2 * pow];
// Transfers the input array into the last half of the segment tree array
Array.Copy(arr, 0, Tree, pow, arr.Length);
// Calculates the first half
for (var i = pow - 1; i > 0; --i)
{
Tree[i] = Tree[Left(i)] + Tree[Right(i)];
}
}
/// <summary>Gets the segment tree array.</summary>
public int[] Tree { get; }
/// <summary>
/// Starts a query.
/// Runtime complexity: O(logN) where n equals the array-length.
/// </summary>
/// <param name="l">Left border of the query.</param>
/// <param name="r">Right border of the query.</param>
/// <returns>Sum of the subarray between <c>l</c> and <c>r</c> (including <c>l</c> and <c>r</c>).</returns>
// Editing of query start at node with 1.
// Node with index 1 includes the whole input subarray.
public int Query(int l, int r) =>
Query(++l, ++r, 1, Tree.Length / 2, 1);
/// <summary>
/// Calculates the right child of a node.
/// </summary>
/// <param name="node">Current node.</param>
/// <returns>Index of the right child.</returns>
protected int Right(int node) => 2 * node + 1;
/// <summary>
/// Calculates the left child of a node.
/// </summary>
/// <param name="node">Current node.</param>
/// <returns>Index of the left child.</returns>
protected int Left(int node) => 2 * node;
/// <summary>
/// Calculates the parent of a node.
/// </summary>
/// <param name="node">Current node.</param>
/// <returns>Index of the parent node.</returns>
protected int Parent(int node) => node / 2;
/// <summary>
/// Edits a query.
/// </summary>
/// <param name="l">Left border of the query.</param>
/// <param name="r">Right border of the query.</param>
/// <param name="a">Left end of the subarray enclosed by <c>i</c>.</param>
/// <param name="b">Right end of the subarray enclosed by <c>i</c>.</param>
/// <param name="i">Current node.</param>
/// <returns>Sum of a subarray between <c>l</c> and <c>r</c> (including <c>l</c> and <c>r</c>).</returns>
protected virtual int Query(int l, int r, int a, int b, int i)
{
// If a and b are in the (by l and r) specified subarray
if (l <= a && b <= r)
{
return Tree[i];
}
// If a or b are out of the by l and r specified subarray
if (r < a || b < l)
{
// Returns the neutral value of the operation
// (in this case 0, because x + 0 = x)
return 0;
}
// Calculates index m of the node that cuts the current subarray in half
var m = (a + b) / 2;
// Start query of new two subarrays a:m and m+1:b
// The right and left child cover this intervals
return Query(l, r, a, m, Left(i)) + Query(l, r, m + 1, b, Right(i));
}
}