forked from TheAlgorithms/C-Sharp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SegmentTreeApply.cs
110 lines (98 loc) · 4.46 KB
/
SegmentTreeApply.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
104
105
106
107
108
109
110
using System;
namespace DataStructures.SegmentTrees
{
/// <summary>
/// This is an extension of a segment tree, which allows applying distributive operations to a subarray
/// (in this case multiplication).
/// </summary>
public class SegmentTreeApply : SegmentTree
{
/// <summary>
/// Initializes a new instance of the <see cref="SegmentTreeApply" /> class.
/// Runtime complexity: O(n) where n equals the array-length.
/// </summary>
/// <param name="arr">Array on which the operations should be made.</param>
public SegmentTreeApply(int[] arr)
: base(arr)
{
// Initilizes and fills "operand" array with neutral element (in this case 1, because value * 1 = value)
Operand = new int[Tree.Length];
Array.Fill(Operand, 1);
}
/// <summary>
/// Gets an array that stores for each node an operand,
/// which must be applied to all direct and indirect child nodes of this node
/// (but not to the node itself).
/// </summary>
public int[] Operand { get; }
/// <summary>
/// Applies a distributive operation to a subarray defined by <c>l</c> and <c>r</c>
/// (in this case multiplication by <c>value</c>).
/// Runtime complexity: O(logN) where N equals the initial array-length.
/// </summary>
/// <param name="l">Left border of the subarray.</param>
/// <param name="r">Right border of the subarray.</param>
/// <param name="value">Value with which each element of the interval is calculated.</param>
public void Apply(int l, int r, int value)
{
// The Application start at node with 1
// Node with index 1 includes the whole input subarray
Apply(++l, ++r, value, 1, Tree.Length / 2, 1);
}
/// <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 override int Query(int l, int r, int a, int b, int i)
{
if (l <= a && b <= r)
{
return Tree[i];
}
if (r < a || b < l)
{
return 0;
}
var m = (a + b) / 2;
// Application of the saved operand to the direct and indrect child nodes
return Operand[i] * (Query(l, r, a, m, Left(i)) + Query(l, r, m + 1, b, Right(i)));
}
/// <summary>
/// Applies the operation.
/// </summary>
/// <param name="l">Left border of the Application.</param>
/// <param name="r">Right border of the Application.</param>
/// <param name="value">Multiplier by which the subarray is to be multiplied.</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>
private void Apply(int l, int r, int value, int a, int b, int i)
{
// If a and b are in the (by l and r) specified subarray
if (l <= a && b <= r)
{
// Applies the operation to the current node and saves it for the direct and indirect child nodes
Operand[i] = value * Operand[i];
Tree[i] = value * Tree[i];
return;
}
// If a or b are out of the by l and r specified subarray stop application at this node
if (r < a || b < l)
{
return;
}
// Calculates index m of the node that cuts the current subarray in half
var m = (a + b) / 2;
// Applies the operation to both halfes
Apply(l, r, value, a, m, Left(i));
Apply(l, r, value, m + 1, b, Right(i));
// Recalculates the value of this node by its (possibly new) children.
Tree[i] = Operand[i] * (Tree[Left(i)] + Tree[Right(i)]);
}
}
}