結果
問題 | No.880 Yet Another Segment Tree Problem |
ユーザー | 7deQSJCy8c4Hg7I |
提出日時 | 2024-09-02 18:33:19 |
言語 | C++23 (gcc 12.3.0 + boost 1.83.0) |
結果 |
WA
|
実行時間 | - |
コード長 | 26,724 bytes |
コンパイル時間 | 6,153 ms |
コンパイル使用メモリ | 336,276 KB |
実行使用メモリ | 30,628 KB |
最終ジャッジ日時 | 2024-09-02 18:33:53 |
合計ジャッジ時間 | 32,102 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
6,816 KB |
testcase_01 | WA | - |
testcase_02 | WA | - |
testcase_03 | WA | - |
testcase_04 | WA | - |
testcase_05 | WA | - |
testcase_06 | WA | - |
testcase_07 | WA | - |
testcase_08 | WA | - |
testcase_09 | WA | - |
testcase_10 | WA | - |
testcase_11 | WA | - |
testcase_12 | WA | - |
testcase_13 | WA | - |
testcase_14 | WA | - |
testcase_15 | WA | - |
testcase_16 | WA | - |
testcase_17 | WA | - |
testcase_18 | WA | - |
testcase_19 | AC | 637 ms
23,472 KB |
testcase_20 | AC | 623 ms
23,520 KB |
testcase_21 | AC | 661 ms
23,576 KB |
testcase_22 | AC | 605 ms
23,564 KB |
testcase_23 | AC | 653 ms
23,468 KB |
testcase_24 | AC | 507 ms
23,588 KB |
testcase_25 | AC | 549 ms
23,456 KB |
testcase_26 | AC | 527 ms
23,540 KB |
testcase_27 | AC | 506 ms
23,636 KB |
testcase_28 | AC | 548 ms
23,408 KB |
testcase_29 | WA | - |
testcase_30 | WA | - |
testcase_31 | WA | - |
testcase_32 | AC | 104 ms
23,564 KB |
testcase_33 | TLE | - |
testcase_34 | -- | - |
testcase_35 | -- | - |
testcase_36 | -- | - |
testcase_37 | -- | - |
ソースコード
#include <bits/stdc++.h> using namespace std; #include <atcoder/all> #include <cassert> #include <cmath> #include <functional> #include <iostream> #include <vector> using namespace atcoder; using ll = long long; using ld = long double; using Graph = vector<vector<int>>; using vi = vector<int>; using vl = vector<long>; using vll = vector<long long>; using vb = vector<bool>; using vvi = vector<vi>; using vvl = vector<vl>; using vvb = vector<vb>; using vvvb = vector<vvb>; using vvll = vector<vll>; using vvvll = vector<vvll>; using vvvvll = vector<vvvll>; using vvvvvll = vector<vvvvll>; using vd = vector<double>; using vvd = vector<vd>; using vvvd = vector<vvd>; using vld = vector<long double>; using vvld = vector<vld>; using vvvld = vector<vvld>; using vc = vector<char>; using vvc = vector<vc>; using lll = __int128_t; using vs = vector<string>; using pii = pair<long long, long long>; using mint = modint1000000007; #define mp make_pair #define reps(i, a, n) for (ll i = (a); i < (ll)(n); i++) #define rep(i, n) for (ll i = (0); i < (ll)(n); i++) #define rrep(i, n) for (ll i = (1); i < (ll)(n + 1); i++) #define repd(i, n) for (ll i = n - 1; i >= 0; i--) #define rrepd(i, n) for (ll i = n; i >= 1; i--) #define ALL(n) n.begin(), n.end() #define rALL(n) n.rbegin(), n.rend() #define fore(i, a) for (auto &i : a) #define IN(a, x, b) (a <= x && x < b) #define IN(a, x, b) (a <= x && x < b) #define INIT \ std::ios::sync_with_stdio(false); \ std::cin.tie(0); std::random_device seed_gen; std::mt19937_64 engine(seed_gen()); template <class T> void output(T &W, bool x) { cout << W; if (!x) cout << ' '; else cout << endl; return; } // sは改行するか否かを表す template <class T> void output(vector<T> &W, bool s) { rep(i, W.size()) { output(W[i], ((i == W.size() - 1) || s)); } return; } // sは改行するか否かを表す template <class T> void output(vector<vector<T>> &W, bool s) { rep(i, W.size()) { output(W[i], s); } return; } template <class T> T vectorsum(vector<T> &W, int a, int b) { return accumulate(W.begin() + a, W.end() + b, (T)0); } template <class T> T vectorsum(vector<T> &W) { int b = W.size(); return accumulate(ALL(W), (T)0); } template <class T> inline T CHMAX(T &a, const T b) { return a = (a < b) ? b : a; } template <class T> inline T CHMIN(T &a, const T b) { return a = (a > b) ? b : a; } template <class T> void input(T &W) { cin >> W; return; } template <class T> void input(vector<T> &W) { for (auto &u : W) input(u); return; } template <class T, class TT> void add(T &W, TT &a) { W += a; return; } template <class T> void add(vector<T> &W, vector<T> &a) { rep(i, W.size()) add(W[i], a[i]); } template <class T> void add(T &W, T &a) { W += a; } template <class T, class TT> void add(vector<T> &W, TT a) { for (auto &u : W) add(u, a); return; } template <class T, class TT> void mul(T &W, TT &a) { W *= a; return; } template <class T, class TT> void mul(vector<T> &W, TT a) { for (auto &u : W) mul(u, a); return; } // [a,b)の乱数生成 long long randomINT(ll a, ll b) { unsigned long long c = engine(); c %= (b - a); c += a; return c; } const double PI = acos(-1.0L); const long double EPS = 1e-10; const double INF = 1e18; __int128_t Power(__int128_t a, __int128_t b, __int128_t m) { __int128_t p = a, Answer = 1; for (int i = 0; i < 63; i++) { ll wari = (1LL << i); if ((b / wari) % 2 == 1) { Answer %= m; Answer = (Answer * p) % m; // 「a の 2^i 乗」が掛けられるとき } p %= m; p = (p * p) % m; } return Answer; } void Yes(bool b) { if (b) cout << "Yes" << endl; else cout << "No" << endl; } template <typename T> vector<T> dycstra(vector<vector<pair<ll, T>>> G, ll N, ll K) { vb kaku(N, false); vector<T> cur(N, INF); cur[K] = 0; priority_queue<pair<T, ll>, vector<pair<T, ll>>, greater<pair<T, ll>>> Q; Q.push(make_pair(cur[K], K)); while (!Q.empty()) { ll pos = Q.top().second; Q.pop(); if (kaku[pos]) continue; kaku[pos] = true; for (ll i = 0; i < G[pos].size(); i++) { ll nex = G[pos][i].first; T cost = G[pos][i].second; if (cur[nex] > cur[pos] + cost - EPS) { cur[nex] = cur[pos] + cost; Q.push(make_pair(cur[nex], nex)); } } } return cur; } ll randamX(ll K) { ll a = engine(); a %= (K - 1); a++; return a; } template <typename T> // [0,M)についての階上を求める vector<T> KAI(int M) { vector<T> kai(M, 1); rep(i, M - 1) { kai[i + 1] = kai[i] * (i + 1); } return kai; } template <typename T> vector<T> DIV(int M) { vector<T> kai = KAI<T>(M), div(M, 1); rep(i, M - 1) { div[i + 1] = 1 / kai[i + 1]; } return div; } /* 関数名 n_ary(string str, int n, int m) 説明 n 進数で表現された数値を文字列 str で受け取り、m 進数に直して文字列で出力する。 使用ライブラリ string 使用自作関数 ntodec, decton, pow_ll 制約事項 36進数までの対応。負の値には対応していない。 */ string n_ary(string &str, int n, int m) { str = ""; while (n) { str.push_back('0' + n % m); n /= m; } reverse(ALL(str)); return str; } template <typename T> vector<T> compress(vector<T> &X) { // ソートした結果を vals に vector<T> vals = X; sort(vals.begin(), vals.end()); // 隣り合う重複を削除(unique), 末端のゴミを削除(erase) vals.erase(unique(vals.begin(), vals.end()), vals.end()); // 各要素ごとに二分探索で位置を求める for (int i = 0; i < (int)X.size(); i++) { X[i] = lower_bound(vals.begin(), vals.end(), X[i]) - vals.begin(); } return vals; } long long extGCD(long long a, long long b, long long &x, long long &y) { if (b == 0) { x = 1; y = 0; return a; } long long d = extGCD(b, a % b, y, x); y -= a / b * x; return d; } std::ostream &operator<<(std::ostream &dest, __int128_t value) { std::ostream::sentry s(dest); if (s) { __uint128_t tmp = value < 0 ? -value : value; char buffer[128]; char *d = std::end(buffer); do { --d; *d = "0123456789"[tmp % 10]; tmp /= 10; } while (tmp != 0); if (value < 0) { --d; *d = '-'; } int len = std::end(buffer) - d; if (dest.rdbuf()->sputn(d, len) != len) { dest.setstate(std::ios_base::badbit); } } return dest; } // 削除可能priorty_queue struct eraseable_priority_queue { priority_queue<ll> Q1, Q2; void push(ll K) { Q1.emplace(K); } void erase(ll K) { Q2.emplace(K); } ll top() { while (!Q1.empty() && Q2.top() != Q1.top()) Q1.pop(), Q2.pop(); return Q1.top(); } bool empty() { while (!Q1.empty() && Q2.top() != Q1.top()) Q1.pop(), Q2.pop(); return Q1.empty(); } }; struct TRI { ll a; ll b; ll c; ll d; }; bool operator>(const TRI &r, const TRI &l) { return (r.a > l.a | (r.a == l.a & r.b > l.b) | (r.a == l.a & r.b == l.b & r.c > l.c)); } bool operator<(const TRI &r, const TRI &l) { return (r.a < l.a | (r.a == l.a & r.b < l.b) | (r.a == l.a & r.b == l.b & r.c < l.c)); } // 通常の素因数分解(O(√N)) vll prime_factor(ll N) { vll A; for (ll i = 2; i * i <= N; i++) { // cout << i << endl; if (N % i == 0) { while (N % i == 0) { N /= i; A.push_back(i); } } } if (N != 1) A.push_back(N); return A; } #include <bits/stdc++.h> using namespace std; // 参考: https://smijake3.hatenablog.com/entry/2019/04/28/021457 namespace Segment_Tree_Beats_INVAl { // 型の指定 using R = long long; // deta・RSQ 用の型 struct T { R sum; R left; bool same; T(R x) : sum(x), left(x), same(true) {} T() : sum(0), left(0), same(true) {}; }; R inf = 1e18; // 任意の遅延伝搬用の型 using E = long long; // モノイドの結合律(足し算とか掛け算とか) T op(T a, T b) { T ret; ret.sum = a.sum + b.sum; ret.left = a.left; ret.same = (a.same && b.same && ((a.left == b.left))); return ret; } // モノイドの単位元 T e() { return T(); } // max,minの更新処置によってデータそのものに影響を与える関数(データの値、更新値、最大(小)値、cの個数) T f(T a, R b, R c, int len) { T ret; ret.sum = a.sum + len * (b - c); ret.left = b; ret.same = true; return ret; } // dataに対する遅延伝搬(今回は除算を行うので長さは不要) // 要素単体の更新は長さ1の区間の更新ととらえればいい。 T mapping(E a, T b, int len) { T ret; if (b.sum == 0 || a == inf) return b; ret.left = gcd(a, b.left); ret.sum = ret.left * len; ret.same = b.same; return ret; } // aが後の操作 E composition(E a, E b) { if (b == inf) return a; if (a == inf) return b; return gcd(a, b); } E id() { return inf; } struct Segment_Tree_Beats { private: int n{}, sz{}, height{}; vector<T> data; // ノードの長さを表す配列 vector<int> Len; // 1番目・2番目(最大値) vector<R> max_v, smax_v; // 1番目・2番目(最小値) vector<R> min_v, smin_v; // 最大値・最小値の個数 vector<int> max_c, min_c; // 任意の遅延伝搬(単位元はid()) vector<E> lazy; void update(int k) { data[k] = op(data[2 * k], data[2 * k + 1]); if (max_v[2 * k] > max_v[2 * k + 1]) { max_v[k] = max_v[2 * k]; smax_v[k] = max(smax_v[2 * k], max_v[2 * k + 1]); max_c[k] = max_c[2 * k]; } else if (max_v[2 * k] < max_v[2 * k + 1]) { max_v[k] = max_v[2 * k + 1]; smax_v[k] = max(smax_v[2 * k + 1], max_v[2 * k]); max_c[k] = max_c[2 * k + 1]; } else { max_v[k] = max_v[2 * k]; smax_v[k] = max(smax_v[2 * k], smax_v[2 * k + 1]); max_c[k] = max_c[2 * k] + max_c[2 * k + 1]; } if (min_v[2 * k] < min_v[2 * k + 1]) { min_v[k] = min_v[2 * k]; smin_v[k] = min(smin_v[2 * k], min_v[2 * k + 1]); min_c[k] = min_c[2 * k]; } else if (min_v[2 * k] > min_v[2 * k + 1]) { min_v[k] = min_v[2 * k + 1]; smin_v[k] = min(smin_v[2 * k + 1], min_v[2 * k]); min_c[k] = min_c[2 * k + 1]; } else { min_v[k] = min_v[2 * k]; smin_v[k] = min(smin_v[2 * k], smin_v[2 * k + 1]); min_c[k] = min_c[2 * k] + min_c[2 * k + 1]; } } void push(int k) { if(lazy[k]!=id()) { apply_push(k); return; } max_push(k); min_push(k); } /*chminに用いる関数*/ // 最大値を親ノードから子ノードへの伝搬 void max_push(int k) { // cout << "max " << k << ' ' << max_v[k] << ' ' << max_v[k*2] << ' ' << max_v[k*2+1] << endl; if (max_v[k] < max_v[2 * k]) { // cout << "max " << k << ' ' << max_v[k] << ' ' << max_v[k*2] << endl; push_min(2 * k, max_v[k]); } if (max_v[k] < max_v[2 * k + 1]) { // cout << "max " << k << ' ' << max_v[k] << ' ' << max_v[k*2]+1 << endl; push_min(2 * k + 1, max_v[k]); } } // chminによる関数の値の更新 void push_min(int k, R x) { /// cout << "max " << k << ' ' << x << ' ' << max_v[k] << endl; data[k] = f(data[k], x, max_v[k], max_c[k]); // 最小値も必要に応じて更新 if (max_v[k] == min_v[k]) { max_v[k] = min_v[k] = x; } else if (max_v[k] == smin_v[k]) { max_v[k] = smin_v[k] = x; } else { max_v[k] = x; } // cout << "max " << k << ' ' << x << ' ' << max_v[k] << endl; } void max_all_apply(int k, R x) { // 更新する箇所が存在しないので終わり if (max_v[k] <= x) return; // 更新する箇所が一か所のみであるので更新して終わり else if (smax_v[k] < x) { push_min(k, x); return; } // 今いる区間の全ての更新を追えたら子ノードに行って更新をし、ボトムアップで親ノードに更新する push(k); max_all_apply(2 * k, x); max_all_apply(2 * k + 1, x); update(k); } /*ここまで*/ /*chmaxに用いる関数*/ // 最小値を親ノードから子ノードへの伝搬 void min_push(int k) { // cout << "min " << k << ' ' << min_v[k] << ' ' << min_v[k*2] << ' ' << min_v[k*2+1] << endl; if (min_v[k] > min_v[2 * k]) { push_max(2 * k, min_v[k]); } if (min_v[k] > min_v[2 * k + 1]) { push_max(2 * k + 1, min_v[k]); } } // xに対応して最小値とデータの値の更新 void push_max(int k, R x) { data[k] = f(data[k], x, min_v[k], min_c[k]); if (min_v[k] == max_v[k]) { min_v[k] = max_v[k] = x; } else if (min_v[k] == smax_v[k]) { min_v[k] = smax_v[k] = x; } else { min_v[k] = x; } } void min_all_apply(int k, R x) { // 更新する箇所が存在しないので終わり if (x <= min_v[k]) return; // 更新する箇所が一か所のみであるので更新して終わり else if (x < smin_v[k]) { push_max(k, x); return; } // 今いる区間の全ての更新を追えたら子ノードに行って更新をし、ボトムアップで親ノードに更新する push(k); min_all_apply(2 * k, x); min_all_apply(2 * k + 1, x); update(k); } /*ここまで*/ void apply_push(int k) { all_apply(2 * k, lazy[k]); all_apply(2 * k + 1, lazy[k]); lazy[k] = id(); } void push_apply(int k, E x) { if (x == id()) return; /// cout << k << ' ' << max_v[k] << ' ' << x << endl; max_v[k] = mapping(x, max_v[k], 1).sum; // cout << k << ' ' << max_v[k] << ' ' << x << endl; if (smax_v[k] != -inf) smax_v[k] = mapping(x, smax_v[k], 1).sum; min_v[k] = mapping(x, min_v[k], 1).sum; if (smin_v[k] != inf) smin_v[k] = mapping(x, smin_v[k], 1).sum; max_c[k] = Len[k]; min_c[k] = Len[k]; data[k] = mapping(x, data[k], Len[k]); lazy[k] = composition(x, lazy[k]); } // 抽象遅延伝搬作業 void all_apply(int k, E x) { push_apply(k, x); if (!data[k].same) { push(k); update(k); } } public: Segment_Tree_Beats() = default; explicit Segment_Tree_Beats(int n) : Segment_Tree_Beats(vector<R>(n, 0)) {} explicit Segment_Tree_Beats(const vector<R> &v) : n(v.size()) { sz = 1; height = 0; while (sz < n) sz <<= 1, height++; data = vector<T>(2 * sz, e()); lazy = vector<E>(2 * sz, id()); Len = vector<int>(2 * sz, 0); max_v.resize(2 * sz, -inf), min_v.resize(2 * sz, inf); smax_v.resize(2 * sz, -inf), smin_v.resize(2 * sz, inf); max_c.resize(2 * sz, 0), min_c.resize(2 * sz, 0); build(v); } void build(const vector<R> &v) { assert(n == (int)v.size()); for (int k = 0; k < n; k++) { data[k + sz] = T(v[k]); max_v[k + sz] = v[k], min_v[k + sz] = v[k]; max_c[k + sz] = 1, min_c[k + sz] = 1; Len[k + sz] = 1; } for (int k = sz - 1; k > 0; k--) update(k), Len[k] = Len[2 * k] + Len[2 * k + 1]; } void set(int k, const T x) { assert(0 <= k && k < n); k += sz; for (int i = height; i > 0; i--) push(k >> i); data[k] = x; for (int i = 1; i <= height; i++) update(k >> i); } T get(int k) { assert(0 <= k && k < n); k += sz; for (int i = height; i > 0; i--) push(k >> i); return data[k]; } T operator[](int k) { return get(k); } // i=l,...r-1においてmin(v[i],x)に更新 void range_chmin(int l, int r, R x) { if (l >= r) return; l += sz; r += sz; // 更新する区間を部分的に含んだ区間においてトップダウンで子ノードに伝搬させながらdataの値を更新 for (int i = height; i > 0; i--) { if (((l >> i) << i) != l) push(l >> i); if (((r >> i) << i) != r) push((r - 1) >> i); } // 値を更新する区間のdataとlazyの値を更新 int l2 = l, r2 = r; for (; l < r; l >>= 1, r >>= 1) { if (l & 1) max_all_apply(l++, x); if (r & 1) max_all_apply(--r, x); } l = l2, r = r2; // 更新する区間を部分的に含んだ区間においてボトムアップで子ノードに伝搬させながらdataの値を更新 for (int i = 1; i <= height; i++) { if (((l >> i) << i) != l) update(l >> i); if (((r >> i) << i) != r) update((r - 1) >> i); } } // i=l,...r-1においてmax(v[i],x)に更新 void range_chmax(int l, int r, R x) { if (l >= r) return; l += sz; r += sz; // 更新する区間を部分的に含んだ区間においてトップダウンで子ノードに伝搬させながらdataの値を更新 for (int i = height; i > 0; i--) { if (((l >> i) << i) != l) push(l >> i); if (((r >> i) << i) != r) push((r - 1) >> i); } // 値を更新する区間のdataとlazyの値を更新 int l2 = l, r2 = r; for (; l < r; l >>= 1, r >>= 1) { if (l & 1) min_all_apply(l++, x); if (r & 1) min_all_apply(--r, x); } l = l2, r = r2; // 更新する区間を部分的に含んだ区間においてボトムアップで子ノードに伝搬させながらdataの値を更新 for (int i = 1; i <= height; i++) { if (((l >> i) << i) != l) update(l >> i); if (((r >> i) << i) != r) update((r - 1) >> i); } } // i=l,...r-1においてv[i]=x void range_update(int l, int r, R x) { range_chmax(l, r, x), range_chmin(l, r, x); } // i=l,...r-1においてmapping(x,v[i]) void range_apply(int l, int r, E x) { if (l >= r) return; l += sz; r += sz; // 更新する区間を部分的に含んだ区間においてトップダウンで子ノードに伝搬させながらdataの値を更新 for (int i = height; i > 0; i--) { if (((l >> i) << i) != l) push(l >> i); if (((r >> i) << i) != r) push((r - 1) >> i); } // 値を更新する区間のdataとlazyの値を更新 int l2 = l, r2 = r; for (; l < r; l >>= 1, r >>= 1) { if (l & 1) all_apply(l++, x); if (r & 1) all_apply(--r, x); } l = l2, r = r2; // 更新する区間を部分的に含んだ区間においてボトムアップで子ノードに伝搬させながらdataの値を更新 for (int i = 1; i <= height; i++) { if (((l >> i) << i) != l) update(l >> i); if (((r >> i) << i) != r) update((r - 1) >> i); } } // op(A[l],A[l+1],...,A[r-1])を求める T prod(int l, int r) { assert(0 <= l && l <= r && r <= n); if (l >= r) return e(); l += sz; r += sz; // 更新する区間を部分的に含んだ区間においてトップダウンで子ノードに伝搬させながらdataの値を更新 for (int i = height; i > 0; i--) { if (((l >> i) << i) != l) push(l >> i); if (((r >> i) << i) != r) push((r - 1) >> i); } T L = e(), R = e(); // 値をチェックする区間のdataの値をチェック for (; l < r; l >>= 1, r >>= 1) { if (l & 1) L = op(L, data[l++]); if (r & 1) R = op(data[--r], R); } return op(L, R); } // max(A[l],A[l+1],...A[r-1])を求める R prod_max(int l, int r) { assert(0 <= l && l <= r && r <= n); if (l >= r) return -inf; l += sz; r += sz; // 更新する区間を部分的に含んだ区間においてトップダウンで子ノードに伝搬させながらdataの値を更新 for (int i = height; i > 0; i--) { if (((l >> i) << i) != l) push(l >> i); if (((r >> i) << i) != r) push((r - 1) >> i); } R L = -inf, R = -inf; // 値をチェックする区間のdataの値をチェック for (; l < r; l >>= 1, r >>= 1) { if (l & 1) L = max(L, max_v[l++]); if (r & 1) R = max(max_v[--r], R); } return max(L, R); } // min(A[l],A[l+1],...A[r-1])を求める R prod_min(int l, int r) { assert(0 <= l && l <= r && r <= n); if (l >= r) return inf; l += sz; r += sz; // 更新する区間を部分的に含んだ区間においてトップダウンで子ノードに伝搬させながらdataの値を更新 for (int i = height; i > 0; i--) { if (((l >> i) << i) != l) push(l >> i); if (((r >> i) << i) != r) push((r - 1) >> i); } R L = inf, R = inf; // 値をチェックする区間のdataの値をチェック for (; l < r; l >>= 1, r >>= 1) { if (l & 1) L = min(L, min_v[l++]); if (r & 1) R = min(min_v[--r], R); } return min(L, R); } T all_prod() const { return data[1]; } // lに対しcheck(op(A[l],A[l+1],...A[r]))=trueとなる最大のrを返す template <typename C> int max_right(int l, const C check) { if (l >= n) return n; l += sz; for (int i = height; i > 0; i--) push(l >> i); T sum = e(); do { while ((l & 1) == 0) l >>= 1; if (check(op(sum, data[l]))) { while (l < sz) { push(l); l <<= 1; auto nxt = op(sum, data[l]); if (not check(nxt)) { sum = nxt; l++; } } return l + 1 - sz; } sum = op(sum, data[l++]); } while ((l & -l) != l); return n; } // rに対しcheck(op(A[l],A[l+1],...A[r]))=trueとなる最小のlを返す template <typename C> int min_left(int r, const C &check) { if (r <= 0) return 0; r += sz; for (int i = height; i > 0; i--) push((r - 1) >> i); T sum = e(); do { r--; while (r > 1 and (r & 1)) r >>= 1; if (check(op(data[r], sum))) { while (r < sz) { push(r); r = (r << 1) + 1; auto nxt = op(data[r], sum); if (not check(nxt)) { sum = nxt; r--; } } return r - sz; } sum = op(data[r], sum); } while ((r & -r) != r); return 0; } // lに対しcheck(max(A[l],A[l+1],...A[r]))=trueとなる最大のrを返す template <typename C> int maximum_max_right(int l, const C check) { if (l >= n) return n; l += sz; for (int i = height; i > 0; i--) push(l >> i); R sum = -inf; do { while ((l & 1) == 0) l >>= 1; if (check(max(sum, max_v[l]))) { while (l < sz) { push(l); l <<= 1; auto nxt = max(sum, max_v[l]); if (not check(nxt)) { sum = nxt; l++; } } return l + 1 - sz; } sum = max(sum, max_v[l++]); } while ((l & -l) != l); return n; } // rに対しcheck(max(A[l],A[l+1],...A[r]))=trueとなる最小のlを返す template <typename C> int maximum_min_left(int r, const C &check) { if (r <= 0) return 0; r += sz; for (int i = height; i > 0; i--) push((r - 1) >> i); R sum = -inf; do { r--; while (r > 1 and (r & 1)) r >>= 1; if (check(max(max_v[r], sum))) { while (r < sz) { push(r); r = (r << 1) + 1; auto nxt = max(max_v[r], sum); if (not check(nxt)) { sum = nxt; r--; } } return r - sz; } sum = max(max_v[r], sum); } while ((r & -r) != r); return 0; } // lに対しcheck(min(A[l],A[l+1],...A[r-1]))=trueとなる最大のrを返す template <typename C> int minimum_max_right(int l, const C check) { if (l >= n) return n; l += sz; for (int i = height; i > 0; i--) push(l >> i); R sum = inf; do { while ((l & 1) == 0) l >>= 1; if (check(min(sum, min_v[l]))) { while (l < sz) { push(l); l <<= 1; auto nxt = min(sum, min_v[l]); if (not check(nxt)) { sum = nxt; l++; } } return l + 1 - sz; } sum = max(sum, min_v[l++]); } while ((l & -l) != l); return n; } // rに対しcheck(min(A[l],A[l+1],...A[r-1]))=trueとなる最小のlを返す template <typename C> int minimum_min_left(int r, const C &check) { if (r <= 0) return 0; r += sz; for (int i = height; i > 0; i--) push((r - 1) >> i); R sum = inf; do { r--; while (r > 1 and (r & 1)) r >>= 1; if (check(min(min_v[r], sum))) { while (r < sz) { push(r); r = (r << 1) + 1; auto nxt = min(min_v[r], sum); if (not check(nxt)) { sum = nxt; r--; } } return r - sz; } sum = min(min_v[r], sum); } while ((r & -r) != r); return 0; } }; } // namespace Segment_Tree_Beats_INVAl using Segment_Tree_Beats_INVAl::Segment_Tree_Beats; // set(k,x) A[k]=xに更新 // get(k,x) A[k]を返す // prod(l,r) : op(A[l],A[l+1],...,A[r-1])を求める // prod_min(l,r) : min(A[l],A[l+1],...,A[r-1])を求める // prod_max(l,r) : max(A[l],A[l+1],...,A[r-1])を求める // update_min(l,r,x) : i=l,...r-1においてA[i]=min(x,A[i])に更新 // update_max(l,r,x) : i=l,...r-1においてA[i]=max(x,A[i])に更新 // update_set(l,r,x) : i=l,...r-1においてA[i]=xに更新 // apply(l,r,x) : i=l,...r-1においてmappinf(x,A[i])を実行 // max_right(l,C) : // lに対しcheck(op(A[l],A[l+1],...A[r]))=trueとなる最大のrを返す // min_left(r, C) // : rに対しcheck(op(A[l],A[l+1],...A[r]))=trueとなる最小のlを返す // maximum_max_right(l,C) : // lに対しcheck(max(A[l],A[l+1],...A[r]))=trueとなる最大のrを返す // maximum_min_left(r, C) : // rに対しcheck(max(A[l],A[l+1],...A[r]))=trueとなる最小のlを返す // manimum_max_right(l,C) : // lに対しcheck(min(A[l],A[l+1],...A[r]))=trueとなる最大のrを返す // manimum_min_left(r, C) : // rに対しcheck(min(A[l],A[l+1],...A[r]))=trueとなる最小のlを返す // Sはdataを表している。 // Sはdataを表している。 using S = ll; using F = ll; S op(ll a, ll b) { return a + b; } S e() { return 0; } S mapping(F f, S x) { return x; } F composition(F f, F g) { return g; } F id() { return 0; } ll half = 499122177; vll dx = {0, 0, 1, -1}; vll dy = {1, -1, 0, 0}; int target; bool f(int v) { return v < target; } int main() { cin.tie(0)->sync_with_stdio(0); cout << fixed << setprecision(20); ll a = 0, b = 0; ll a2, b2, c2; ll a1 = 0, b1 = 0; ll c = 0, c1; ll p = 1; ll N, M; ll t; ll K; ll h, w; ll L; string T; cin >> N >> t; vll A(N); for (int i = 0; i < N; i++) cin >> A[i]; // cout << A.size() << endl; Segment_Tree_Beats seg(A); rep(_, t) { cin >> a >> b >> c; ll d; --b; if (a == 2) { cin >> d; seg.range_apply(b, c, d); } else if (a == 1) { cin >> d; seg.range_update(b, c, d); } else if (a == 4) { cout << seg.prod(b, c).sum << endl; } else { cout << seg.prod_max(b, c) << endl; } } }