結果
問題 | No.880 Yet Another Segment Tree Problem |
ユーザー |
![]() |
提出日時 | 2024-09-02 18:33:19 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.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 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 1 |
other | AC * 11 WA * 21 TLE * 1 -- * 4 |
ソースコード
#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 << ' ';elsecout << 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;elsecout << "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_queuestruct 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/021457namespace 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]=xvoid 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_INVAlusing 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;}}}