Link to this code:
https://cses.fi/paste/faa4d1e27e18c1bdde1772/#include <iostream>
#include <vector>
using namespace std;
#define int long long
const int INF = 1e9 + 5; // 4e18;
const int NEUTRAL = 0; // INF for min, -INF for max, 0 for gcd/sum/XOR
struct SegmentTree {
private:
vector<int> arr, TREE, ADD, SET;
vector<bool> CHANGED;
int merge(int a, int b) {
int res = a + b;
return res;
}
public:
SegmentTree(vector<int> &nums) {
arr = nums;
TREE.resize(4 * nums.size(), NEUTRAL);
ADD.resize(4 * nums.size(), 0);
SET.resize(4 * nums.size(), 0);
CHANGED.resize(4 * nums.size(), 0);
}
void build(int v, int lo, int hi) {
if (lo == hi) {
TREE[v] = arr[lo];
return;
}
int mid = lo + (hi - lo) / 2;
build(2 * v, lo, mid);
build(2 * v + 1, mid + 1, hi);
TREE[v] = merge(TREE[2 * v], TREE[2 * v + 1]);
}
void point_update(int v, int lo, int hi, int i, int x) {
push(v, lo, hi);
if (lo == hi) {
TREE[v] = x;
return;
}
int mid = lo + (hi - lo) / 2;
if (i <= mid) {
point_update(2 * v, lo, mid, i, x);
} else {
point_update(2 * v + 1, mid + 1, hi, i, x);
}
TREE[v] = merge(TREE[2 * v], TREE[2 * v + 1]);
}
void push(int v, int lo, int hi) {
// SET > ADD - SET dominates increments(ADD) in child segments
// SET lazy
if (CHANGED[v]) {
TREE[v] = SET[v] * (hi - lo + 1); // for sum tree -> SET[v] * (hi-lo+1)
if (lo != hi) {
SET[2 * v] = SET[2 * v + 1] = SET[v];
CHANGED[2 * v] = CHANGED[2 * v + 1] = 1;
ADD[2 * v] = ADD[2 * v + 1] = 0;
}
SET[v] = 0;
CHANGED[v] = 0;
}
// ADD lazy
if (ADD[v]) {
TREE[v] += ADD[v] * (hi - lo + 1); // for sum tree -> ADD[v] * (hi-lo+1)
if (lo != hi) {
ADD[2 * v] += ADD[v];
ADD[2 * v + 1] += ADD[v];
}
ADD[v] = 0;
}
}
void range_change(int v, int lo, int hi, int l, int r, int x) {
push(v, lo, hi);
if (r < lo || hi < l) return; // invalid segment
if (l <= lo && hi <= r) { // completely inside/overlap
SET[v] = x;
CHANGED[v] = 1;
push(v, lo, hi);
return;
}
int mid = lo + (hi - lo) / 2;
range_change(2 * v, lo, mid, l, min(mid, r), x);
range_change(2 * v + 1, mid + 1, hi, max(l, mid + 1), r, x);
TREE[v] = merge(TREE[2 * v], TREE[2 * v + 1]);
}
void range_update(int v, int lo, int hi, int l, int r, int x) {
push(v, lo, hi);
if (r < lo || hi < l) return; // invalid segment
if (l <= lo && hi <= r) { // completely inside/overlap
ADD[v] += x;
push(v, lo, hi);
return;
}
int mid = lo + (hi - lo) / 2;
range_update(2 * v, lo, mid, l, min(mid, r), x);
range_update(2 * v + 1, mid + 1, hi, max(l, mid + 1), r, x);
TREE[v] = merge(TREE[2 * v], TREE[2 * v + 1]);
}
int query(int v, int lo, int hi, int l, int r) {
push(v, lo, hi);
if (r < lo || hi < l) return NEUTRAL;
if (l <= lo && hi <= r) return TREE[v];
int mid = lo + (hi - lo) / 2;
return merge(query(2 * v, lo, mid, l, min(mid, r)),
query(2 * v + 1, mid + 1, hi, max(l, mid + 1), r));
}
};
void solve() {
int N, Q;
cin >> N >> Q;
vector<int> arr(N);
for (int &x : arr) cin >> x;
SegmentTree ST = SegmentTree(arr);
ST.build(1, 0, N - 1);
vector<int> qs;
for (int q = 0; q < Q; ++q) {
int ty, l, r, i, x;
cin >> ty;
if (ty == 1) { // update (increment/decrement-point/range)
// set value at index `i` to value `x`
// cin >> i >> x;
// --i; // if i is 0-based;
// ST.point_update(1, 0, N - 1, i, x); // i -> 0..N-1
// NOTE: point update is not using ADD
// increase values in range `l` to `r` with `x`
cin >> l >> r >> x;
--l, --r; // if l & r are 1-based
ST.range_update(1, 0, N - 1, l, r, x); // (l,r) -> 0..N-1
} else if (ty == 2) { // change (value-point/range)
cin >> l >> r >> x;
--l, --r; // if l & r are 1-based
// changes values in range `l` to `r` to `x`
ST.range_change(1, 0, N - 1, l, r, x); // (l,r) -> 0..N-1
} else if (ty == 3) { // query (point/range)
// perform query over range `l` to `r`
cin >> l >> r;
--l, --r; // if l & r are 1-based
int res = ST.query(1, 0, N - 1, l, r); // (l,r) -> 0..N-1
qs.push_back(res);
}
}
for (int x : qs) cout << x << '\n';
}
int32_t main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T = 1;
// cin >> T; // multiple test cases
while (T--) solve();
}