Kyopro Library
 
読み取り中…
検索中…
一致する文字列を見つけられません
segtree_lazy.hpp
[詳解]
1#pragma once
2#include"../../kyopro_library/template.hpp"
3
4/// @brief 遅延評価セグメント木
5/// @tparam Monoid モノイド
6/// @tparam Operator 作用素
7/// @tparam mapping (モノイドの元,作用素の元)→モノイドの元を返す関数
8template<typename Monoid, typename Operator, auto mapping>
9struct SegTreeLazy {
10 using MonoidType=typename Monoid::Type;
11 using OperatorType=typename Operator::Type;
12 SegTreeLazy()=default;
13
14 /// @brief 要素数 n の遅延セグ木を構築する
15 SegTreeLazy(int n) {
16 this->n=n;
17 dat.assign(n<<1,Monoid::id());
18 lazy.assign(n<<1,Operator::id());
19 }
20
21 /// @brief 配列 v から遅延セグ木を構築する
22 SegTreeLazy(const vector<MonoidType>& v) {
23 this->n=v.size();
24 dat.assign(n<<1,Monoid::id());
25 lazy.assign(n<<1,Operator::id());
26 for(int i=0; i<n; i++) dat[i+n]=v[i];
27 for(int i=n-1; i>0; i--) dat[i]=Monoid::op(dat[i<<1],dat[i<<1|1]);
28 }
29
30 /// @brief i 番目の要素を x に更新する
31 void set(int i, MonoidType x) {
32 generate_indices(i,i+1);
33 pushdown();
34 i+=n;
35 dat[i]=x;
36 while(i>>=1) dat[i]=Monoid::op(dat[i<<1],dat[i<<1|1]);
37 }
38
39 /// @brief 区間 [l, r) に x を作用させる
40 void apply(int l, int r, OperatorType x) {
41 if(l==r) return;
42 generate_indices(l,r);
43 pushdown();
44 l+=n,r+=n;
45 while(l<r) {
46 if(l&1) {
47 lazy[l]=Operator::op(lazy[l],x);
48 dat[l]=mapping(dat[l],x);
49 l++;
50 }
51 if(r&1) {
52 r--;
53 lazy[r]=Operator::op(lazy[r],x);
54 dat[r]=mapping(dat[r],x);
55 }
56 l>>=1,r>>=1;
57 }
58 pushup();
59 }
60
61 /// @brief 区間 [l, r) のモノイド積を返す
62 MonoidType fold(int l, int r) {
63 if(l==r) return Monoid::id();
64 generate_indices(l,r);
65 pushdown();
66 MonoidType retl=Monoid::id(),retr=Monoid::id();
67 l+=n,r+=n;
68 while(l<r) {
69 if(l&1) retl=Monoid::op(retl,dat[l++]);
70 if(r&1) retr=Monoid::op(dat[--r],retr);
71 l>>=1,r>>=1;
72 }
73 return Monoid::op(retl,retr);
74 }
75
76 /// @brief 区間 [l, x) のモノイド積が f を満たすような最大の x >= l を返す
77 /// @attention `f(Monoid::id())=true` が成り立つ必要がある
78 /// @note O(log(N))
79 template<typename F>
80 int find_right(int l, F f) {
81 assert(f(Monoid::id()));
82 if(l==n) return n;
83 generate_indices(l,n);
84 pushdown();
85 l+=n;
86 int r=n+n;
87 vector<int> cand_l,cand_r;
88 while(l<r) {
89 if(l&1) cand_l.push_back(l++);
90 if(r&1) cand_r.push_back(--r);
91 l>>=1,r>>=1;
92 }
93 vector<int> cand=cand_l;
94 reverse(cand_r.begin(),cand_r.end());
95 cand.insert(cand.end(),cand_r.begin(),cand_r.end());
96 MonoidType val=Monoid::id();
97 for(int i:cand) {
98 if(f(Monoid::op(val,dat[i]))) {
99 val=Monoid::op(val,dat[i]);
100 } else {
101 while(i<n) {
102 propagate(i);
103 i<<=1;
104 if(f(Monoid::op(val,dat[i]))) {
105 val=Monoid::op(val,dat[i]);
106 i|=1;
107 }
108 }
109 return i-n;
110 }
111 }
112 return n;
113 }
114
115 /// @brief 区間 [x, r) のモノイド積が f を満たすような最小の x<=r を返す
116 /// @attention `f(Monoid::id())=true` が成り立つ必要がある
117 /// @note O(log(N))
118 template<typename F>
119 int find_left(int r, F f) {
120 assert(f(Monoid::id()));
121 if(r==0) return 0;
122 generate_indices(0,r);
123 pushdown();
124 r+=n;
125 int l=n;
126 vector<int> cand_l,cand_r;
127 while(l<r) {
128 if(l&1) cand_l.push_back(l++);
129 if(r&1) cand_r.push_back(--r);
130 l>>=1,r>>=1;
131 }
132 vector<int> cand=cand_r;
133 reverse(cand_l.begin(),cand_l.end());
134 cand.insert(cand.end(),cand_l.begin(),cand_l.end());
135 MonoidType val=Monoid::id();
136 for(int i:cand) {
137 if(f(Monoid::op(dat[i],val))) {
138 val=Monoid::op(dat[i],val);
139 } else {
140 while(i<n) {
141 propagate(i);
142 i=(i<<1)|1;
143 if(f(Monoid::op(dat[i],val))) {
144 val=Monoid::op(dat[i],val);
145 i^=1;
146 }
147 }
148 return i-n+1;
149 }
150 }
151 return 0;
152 }
153
154 int size() { return n; }
155 MonoidType operator[](int i) { return fold(i,i+1); }
156
157private:
158 int n;
159 vector<MonoidType> dat;
160 vector<OperatorType> lazy;
161 vector<int> indices;
162 void generate_indices(int l, int r) {
163 indices.clear();
164 l+=n,r+=n;
165 int lm=(l/(l&-l))>>1,rm=(r/(r&-r))>>1;
166 while(l<r) {
167 if(l<=lm) indices.push_back(l);
168 if(r<=rm) indices.push_back(r);
169 l>>=1,r>>=1;
170 }
171 while(l) {
172 indices.push_back(l);
173 l>>=1;
174 }
175 }
176 void propagate(int i) {
177 if(i<n) {
178 lazy[i<<1]=Operator::op(lazy[i<<1],lazy[i]);
179 lazy[i<<1|1]=Operator::op(lazy[i<<1|1],lazy[i]);
180 dat[i<<1]=mapping(dat[i<<1],lazy[i]);
181 dat[i<<1|1]=mapping(dat[i<<1|1],lazy[i]);
182 }
183 lazy[i]=Operator::id();
184 }
185 void pushdown() {
186 for(int j=(int)indices.size()-1; j>=0; j--) {
187 int i=indices[j];
188 propagate(i);
189 }
190 }
191 void pushup() {
192 for(int j=0; j<(int)indices.size(); j++) {
193 int i=indices[j];
194 dat[i]=Monoid::op(dat[i<<1],dat[i<<1|1]);
195 }
196 }
197};
198
199#include"../../kyopro_library/others/monoid.hpp"
200#include"../../kyopro_library/others/operator.hpp"
201
202namespace RangeQuery {
203 /// @brief 区間更新 / 区間min
204 /// @tparam max_value 最大値
205 /// @tparam not_exist 存在しない値
206 template<typename T, T max_value, T not_exist>
208 static T mapping(const T& a, const T& b) { return b==not_exist?a:b; }
210 };
211
212 /// @brief 区間更新 / 区間max
213 /// @tparam min_value 最小値
214 /// @tparam not_exist 存在しない値
215 template<typename T, T min_value, T not_exist>
217 static T mapping(const T& a, const T& b) { return b==not_exist?a:b; }
219 };
220
221 /// @brief 区間更新 / 区間和
222 /// @tparam not_exist 存在しない値
223 template<typename T, T not_exist>
225 using S=typename Monoid::SumPair<T>::Type;
226 static S mapping(const S& a, const T& b) { return b==not_exist?a:S{b*a.second,a.second}; }
228 };
229
230 /// @brief 区間加算 / 区間min
231 template<typename T, T max_value>
233 static T mapping(const T& a, const T& b) { return a+b; }
235 };
236
237 /// @brief 区間加算 / 区間max
238 template<typename T, T min_value>
240 static T mapping(const T& a, const T& b) { return a+b; }
242 };
243
244 /// @brief 区間加算 / 区間和
245 template<typename T>
247 using S=typename Monoid::SumPair<T>::Type;
248 static S mapping(const S& a, const T& b) { return {a.first+b*a.second,a.second}; }
250 };
251}
モノイド
Definition monoid.hpp:5
区間クエリ
Definition segtree.hpp:136
(和,区間の長さ)
Definition monoid.hpp:34
区間加算 / 区間max
static T mapping(const T &a, const T &b)
区間加算 / 区間min
static T mapping(const T &a, const T &b)
区間加算 / 区間和
static S mapping(const S &a, const T &b)
区間更新 / 区間max
static T mapping(const T &a, const T &b)
区間更新 / 区間min
static T mapping(const T &a, const T &b)
区間更新 / 区間和
static S mapping(const S &a, const T &b)
遅延評価セグメント木
SegTreeLazy(const vector< MonoidType > &v)
配列 v から遅延セグ木を構築する
void apply(int l, int r, OperatorType x)
区間 [l, r) に x を作用させる
MonoidType fold(int l, int r)
区間 [l, r) のモノイド積を返す
int find_left(int r, F f)
区間 [x, r) のモノイド積が f を満たすような最小の x<=r を返す
MonoidType operator[](int i)
int find_right(int l, F f)
区間 [l, x) のモノイド積が f を満たすような最大の x >= l を返す
void set(int i, MonoidType x)
i 番目の要素を x に更新する
SegTreeLazy()=default
SegTreeLazy(int n)
要素数 n の遅延セグ木を構築する