-
Notifications
You must be signed in to change notification settings - Fork 61
/
segment_tree_lazy.cpp
123 lines (104 loc) · 3.49 KB
/
segment_tree_lazy.cpp
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
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <vector>
#include <cassert>
template<typename T, typename U,
typename TAssociativeCombineFunction,
typename UAssociativeCombineFunction,
typename UApplicator>
struct segment_tree_lazy {
int SZ;
T t_identity;
U u_identity;
TAssociativeCombineFunction TT;
UAssociativeCombineFunction UU;
UApplicator UT;
std::vector<T> data;
std::vector<bool> has_update;
std::vector<U> updates;
segment_tree_lazy() {}
segment_tree_lazy(int _SZ, T _t_identity, U _u_identity,
TAssociativeCombineFunction _TT, UAssociativeCombineFunction _UU, UApplicator _UT)
: SZ(_SZ), t_identity(_t_identity), u_identity(_u_identity), TT(_TT), UU(_UU), UT(_UT) {
data.assign(2 * SZ, t_identity);
has_update.assign(SZ, false);
updates.assign(SZ, u_identity);
}
template<typename Function>
void assign(Function fn) {
for (int i = 0; i < SZ; i++)
data[SZ + i] = fn(i);
for (int i = SZ - 1; i; i--)
data[i] = TT(data[2 * i], data[2 * i + 1]);
has_update.assign(SZ, false);
updates.assign(SZ, u_identity);
}
private:
void apply_update(int i, const U &u) {
data[i] = UT(u, data[i]);
if (i < SZ) {
has_update[i] = true;
updates[i] = UU(u, updates[i]);
}
}
void propagate_ancestor_updates(int i) {
for (int ht = 31 - __builtin_clz(i); ht > 0; ht--) {
int anc = i >> ht;
if (has_update[anc]) {
apply_update(2 * anc, updates[anc]);
apply_update(2 * anc + 1, updates[anc]);
has_update[anc] = false;
updates[anc] = u_identity;
}
}
}
void recompute_ancestors(int i) {
for (i /= 2; i; i /= 2)
data[i] = UT(updates[i], TT(data[2 * i], data[2 * i + 1]));
}
void modify_leaf(int i, T v, bool overwrite) {
i += SZ;
propagate_ancestor_updates(i);
data[i] = overwrite ? v : TT(data[i], v);
recompute_ancestors(i);
}
public:
// Assigns v at index i
void assign(int i, T v) {
modify_leaf(i, v, true);
}
// Replaces the current value at index i with TT(current value, v)
void combine_and_assign(int i, T v) {
modify_leaf(i, v, false);
}
// Applies update u to the elements at indices in [first, last)
void apply_update(int first, int last, U u) {
assert(0 <= first && last <= SZ);
first += SZ, last += SZ;
propagate_ancestor_updates(first);
propagate_ancestor_updates(last - 1);
for (int i = first, j = last; i < j; i /= 2, j /= 2) {
if (i&1) apply_update(i++, u);
if (j&1) apply_update(--j, u);
}
recompute_ancestors(first);
recompute_ancestors(last - 1);
}
// Accumulates the elements at indices in [first, last)
T accumulate(int first, int last) {
assert(0 <= first && last <= SZ);
first += SZ, last += SZ;
propagate_ancestor_updates(first);
propagate_ancestor_updates(last - 1);
T left = t_identity, right = t_identity;
for (int i = first, j = last; i < j; i /= 2, j /= 2) {
if (i&1) left = TT(left, data[i++]);
if (j&1) right = TT(data[--j], right);
}
return TT(left, right);
}
// Returns the current value at index i
T read(int i) {
i += SZ;
propagate_ancestor_updates(i);
return data[i];
}
};