⛳
LazySegTreeを書く
やること
AOJの遅延セグ木の問題を埋める。
RMQ (Range Min Query) and RUQ (Range Update Query)
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
const int BASE = (1 << 19);
const int INF = (1LL << 31) - 1;
using Int = long long;
template <typename T>
using Vec = vector<T>;
class LazySegTree {
private:
Vec<Int> tree, lazy;
public:
LazySegTree(int n) {
tree.assign(2 * BASE, INF);
lazy.assign(2 * BASE, -1);
}
void push(int pos, int sl, int sr) {
if (lazy[pos] != -1) {
tree[pos] = lazy[pos];
if (sr - sl > 1) {
lazy[pos * 2] = lazy[pos];
lazy[pos * 2 + 1] = lazy[pos];
}
lazy[pos] = -1;
}
}
void update(int ql, int qr, Int value, int sl = 0, int sr = BASE, int pos = 1) {
push(pos, sl, sr);
if (qr <= sl || sr <= ql) return;
if (ql <= sl && sr <= qr) {
lazy[pos] = value;
push(pos, sl, sr);
return;
}
int mid = (sl + sr) / 2;
update(ql, qr, value, sl, mid, pos * 2);
update(ql, qr, value, mid, sr, pos * 2 + 1);
tree[pos] = min(tree[pos * 2], tree[pos * 2 + 1]);
}
Int get_min(int ql, int qr, int sl = 0, int sr = BASE, int pos = 1) {
push(pos, sl, sr);
if (qr <= sl || sr <= ql) return INF;
if (ql <= sl && sr <= qr) return tree[pos];
int mid = (sl + sr) / 2;
return min(get_min(ql, qr, sl, mid, pos * 2), get_min(ql, qr, mid, sr, pos * 2 + 1));
}
};
int main() {
int n, q;
cin >> n >> q;
LazySegTree seg(n);
for (int i = 0; i < q; i++) {
int type;
cin >> type;
if (type == 0) {
int s, t, x;
cin >> s >> t >> x;
seg.update(s, t + 1, x);
} else {
int s, t;
cin >> s >> t;
cout << seg.get_min(s, t + 1) << endl;
}
}
return 0;
}
RSQ (Range Sum Query) and RAQ (Range Add Query)
#include<iostream>
#include<vector>
using namespace std;
const int BASE = (1 << 19);
using Int = long long;
template <typename T>
using Vec = vector<T>;
class LazySegTree {
private:
Vec<Int> tree, lazy;
void push(int pos, int sl, int sr) {
if (lazy[pos] != 0) {
tree[pos] += lazy[pos] * (sr - sl);
if (sr - sl > 1) {
lazy[pos * 2] += lazy[pos];
lazy[pos * 2 + 1] += lazy[pos];
}
lazy[pos] = 0;
}
}
public:
LazySegTree(int n) {
tree.assign(2 * BASE, 0);
lazy.assign(2 * BASE, 0);
}
void update(int ql, int qr, Int value, int sl = 0, int sr = BASE, int pos = 1) {
push(pos, sl, sr);
if (qr <= sl || sr <= ql) return;
if (ql <= sl && sr <= qr) {
lazy[pos] += value;
push(pos, sl, sr);
return;
}
int mid = (sl + sr) / 2;
update(ql, qr, value, sl, mid, pos * 2);
update(ql, qr, value, mid, sr, pos * 2 + 1);
tree[pos] = tree[pos * 2] + tree[pos * 2 + 1];
}
Int get_sum(int ql, int qr, int sl = 0, int sr = BASE, int pos = 1) {
push(pos, sl, sr);
if (qr <= sl || sr <= ql) return 0;
if (ql <= sl && sr <= qr) return tree[pos];
int mid = (sl + sr) / 2;
return get_sum(ql, qr, sl, mid, pos * 2) + get_sum(ql, qr, mid, sr, pos * 2 + 1);
}
};
int main() {
int n, q;
cin >> n >> q;
LazySegTree seg(n);
for(int i = 0; i < q; i++) {
int type;
cin >> type;
if (type == 0) {
int s, t, x;
cin >> s >> t >> x;
seg.update(s, t + 1, x);
} else {
int s, t;
cin >> s >> t;
cout << seg.get_sum(s, t + 1) << endl;
}
}
return 0;
}
RMQ (Range Min Query) and RAQ (Range Add Query)
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int BASE = (1 << 17);
const int INF = (1LL << 31) - 1;
using Int = long long;
template <typename T>
using Vec = vector<T>;
class LazySegTree {
private:
Vec<Int> tree, lazy;
void push(int pos, int sl, int sr) {
if (lazy[pos] != 0) {
tree[pos] += lazy[pos];
if (sr - sl > 1) {
lazy[pos * 2] += lazy[pos];
lazy[pos * 2 + 1] += lazy[pos];
}
lazy[pos] = 0;
}
}
public:
LazySegTree(int n) {
tree.assign(2 * BASE, 0);
lazy.assign(2 * BASE, 0);
}
void update(int ql, int qr, Int value, int sl = 0, int sr = BASE, int pos = 1) {
push(pos, sl, sr);
if (qr <= sl || sr <= ql) return;
if (ql <= sl && sr <= qr) {
lazy[pos] += value;
push(pos, sl, sr);
return;
}
int mid = (sl + sr) / 2;
update(ql, qr, value, sl, mid, pos * 2);
update(ql, qr, value, mid, sr, pos * 2 + 1);
tree[pos] = min(tree[pos * 2], tree[pos * 2 + 1]);
}
Int get_min(int ql, int qr, int sl = 0, int sr = BASE, int pos = 1) {
push(pos, sl, sr);
if (qr <= sl || sr <= ql) return INF;
if (ql <= sl && sr <= qr) return tree[pos];
int mid = (sl + sr) / 2;
return min(get_min(ql, qr, sl, mid, pos * 2),
get_min(ql, qr, mid, sr, pos * 2 + 1));
}
};
int main() {
int n, q;
cin >> n >> q;
LazySegTree seg(n);
for (int i = 0; i < q; i++) {
int type;
cin >> type;
if (type == 0) {
int s, t, x;
cin >> s >> t >> x;
seg.update(s, t + 1, x);
} else {
int s, t;
cin >> s >> t;
cout << seg.get_min(s, t + 1) << endl;
}
}
return 0;
}
RSQ (Range Sum Query) and RUQ (Range Update Query)
#include<iostream>
#include<vector>
using namespace std;
const int BASE = (1 << 17);
using Int = long long;
template <typename T>
using Vec = vector<T>;
class LazySegTree {
private:
Vec<Int> tree, lazy;
Vec<bool> pending;
void push(int pos, int sl, int sr) {
if (pending[pos]) {
tree[pos] = lazy[pos] * (sr - sl);
if (sr - sl > 1) {
lazy[pos * 2] = lazy[pos];
lazy[pos * 2 + 1] = lazy[pos];
pending[pos * 2] = pending[pos * 2 + 1] = true;
}
pending[pos] = false;
}
}
public:
LazySegTree(int n) {
tree.assign(2 * BASE, 0);
lazy.assign(2 * BASE, 0);
pending.assign(2 * BASE, false);
}
void update(int ql, int qr, Int value, int sl = 0, int sr = BASE, int pos = 1) {
push(pos, sl, sr);
if (qr <= sl || sr <= ql) return;
if (ql <= sl && sr <= qr) {
lazy[pos] = value;
pending[pos] = true;
push(pos, sl, sr);
return;
}
int mid = (sl + sr) / 2;
update(ql, qr, value, sl, mid, pos * 2);
update(ql, qr, value, mid, sr, pos * 2 + 1);
tree[pos] = tree[pos * 2] + tree[pos * 2 + 1];
}
Int get_sum(int ql, int qr, int sl = 0, int sr = BASE, int pos = 1) {
push(pos, sl, sr);
if (qr <= sl || sr <= ql) return 0;
if (ql <= sl && sr <= qr) return tree[pos];
int mid = (sl + sr) / 2;
return get_sum(ql, qr, sl, mid, pos * 2) + get_sum(ql, qr, mid, sr, pos * 2 + 1);
}
};
int main() {
int n, q;
cin >> n >> q;
LazySegTree seg(n);
for (int i = 0; i < q; i++) {
int type;
cin >> type;
if (type == 0) {
int s, t, x;
cin >> s >> t >> x;
seg.update(s, t + 1, x);
} else {
int s, t;
cin >> s >> t;
cout << seg.get_sum(s, t + 1) << endl;
}
}
return 0;
}
まとめ
- ミニマムの綴りが分からなかったんですけど、スルーしちゃいました。ごめんなさい。
- SegTreeテンプレを某有名競プロYouTuberに倣って作ってから遅延評価ってどういうのだっけ?と考えながら書いていくとやりやすいなと思いました。Lazyの値はどういう値であるか、ということは常に自分に意識させておくとミスが減りそう。
- 半開半閉区間にしています。
- LazySegTreeの多様なパターンに思える問題らに対するコードをページ遷移なしで見比べれたらいいなと思っていたんだけど、見当たらなかったので作りました。
- 至らない部分も散見されるかと思います。何かご意見や気付かれた点がありましたら、温かいご指摘いただけますと幸いです🙏
C++を速く書く方法模索中です、、
Discussion