結果

問題 No.880 Yet Another Segment Tree Problem
ユーザー 7deQSJCy8c4Hg7I7deQSJCy8c4Hg7I
提出日時 2024-09-02 16:29:59
言語 C++23
(gcc 12.3.0 + boost 1.83.0)
結果
WA  
実行時間 -
コード長 26,678 bytes
コンパイル時間 6,556 ms
コンパイル使用メモリ 336,140 KB
実行使用メモリ 30,596 KB
最終ジャッジ日時 2024-09-02 16:30:33
合計ジャッジ時間 32,184 ms
ジャッジサーバーID
(参考情報)
judge3 / judge5
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
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 621 ms
23,472 KB
testcase_20 AC 599 ms
23,588 KB
testcase_21 AC 633 ms
23,568 KB
testcase_22 AC 582 ms
23,584 KB
testcase_23 AC 648 ms
23,504 KB
testcase_24 AC 505 ms
23,548 KB
testcase_25 AC 542 ms
23,592 KB
testcase_26 AC 520 ms
23,504 KB
testcase_27 AC 506 ms
23,576 KB
testcase_28 AC 532 ms
23,412 KB
testcase_29 WA -
testcase_30 WA -
testcase_31 WA -
testcase_32 AC 103 ms
23,636 KB
testcase_33 TLE -
testcase_34 -- -
testcase_35 -- -
testcase_36 -- -
testcase_37 -- -
権限があれば一括ダウンロードができます

ソースコード

diff #

#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;
    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;
    }
  }
}
0