#pragma GCC optimize ("O3") #include "bits/stdc++.h" using namespace std; using ll = long long int; #define debugos cout #define debug(v) {printf("L%d %s > ",__LINE__,#v);debugos<<(v)< ",__LINE__,#v);for(auto e:(v)){debugos< ",__LINE__,#m);for(int x=0;x<(w);x++){debugos<<(m)[x]<<" ";}debugos<\n",__LINE__,#m);for(int y=0;y<(h);y++){for(int x=0;x<(w);x++){debugos<<(m)[y][x]<<" ";}debugos< f) { if (!assertion) { cerr << "assertion fault:" << endl; f(); abort(); } } template inline ostream& operator <<(ostream& o, const pair p) { o << '(' << p.first << ':' << p.second << ')'; return o; } template inline ostream& _ostream_vecprint(ostream& os, const Vec& a) { os << '['; for (const auto& e : a) os << ' ' << e << ' '; os << ']'; return os; } template inline ostream& operator<<(ostream & o, const vector & v) { return _ostream_vecprint(o, v); } template inline ostream& operator<<(ostream & o, const array & v) { return _ostream_vecprint(o, v); } template inline T& chmax(T & to, const T & val) { return to = max(to, val); } template inline T& chmin(T & to, const T & val) { return to = min(to, val); } void bye(string s, int code = 0) { cout << s << endl; exit(code); } mt19937_64 randdev(8901016); template::value>::type* = nullptr> inline T rand(T l, T h, Random & rand = randdev) { return uniform_int_distribution(l, h)(rand); } template::value>::type* = nullptr> inline T rand(T l, T h, Random & rand = randdev) { return uniform_real_distribution(l, h)(rand); } #if defined(_WIN32) || defined(_WIN64) #define getc_x _getc_nolock #define putc_x _putc_nolock #elif defined(__GNUC__) #define getc_x getc_unlocked #define putc_x putc_unlocked #else #define getc_x getc #define putc_x putc #endif #define isvisiblechar(c) (0x21<=(c)&&(c)<=0x7E) class MaiScanner { FILE* fp_; public: inline MaiScanner(FILE* fp) :fp_(fp) {} template void input_integer(T& var) noexcept { var = 0; T sign = 1; int cc = getc_x(fp_); for (; cc < '0' || '9' < cc; cc = getc_x(fp_)) if (cc == '-') sign = -1; for (; '0' <= cc && cc <= '9'; cc = getc_x(fp_)) var = (var << 3) + (var << 1) + cc - '0'; var = var * sign; } inline int c() noexcept { return getc_x(fp_); } inline MaiScanner& operator>>(int& var) noexcept { input_integer(var); return *this; } inline MaiScanner& operator>>(long long& var) noexcept { input_integer(var); return *this; } inline MaiScanner& operator>>(string & var) { int cc = getc_x(fp_); for (; !isvisiblechar(cc); cc = getc_x(fp_)); for (; isvisiblechar(cc); cc = getc_x(fp_)) var.push_back(cc); return *this; } template inline void in(IT begin, IT end) { for (auto it = begin; it != end; ++it) * this >> *it; } }; class MaiPrinter { FILE* fp_; public: inline MaiPrinter(FILE* fp) :fp_(fp) {} template void output_integer(T var) noexcept { if (var == 0) { putc_x('0', fp_); return; } if (var < 0) putc_x('-', fp_), var = -var; char stack[32]; int stack_p = 0; while (var) stack[stack_p++] = '0' + (var % 10), var /= 10; while (stack_p) putc_x(stack[--stack_p], fp_); } inline MaiPrinter& operator<<(char c) noexcept { putc_x(c, fp_); return *this; } inline MaiPrinter& operator<<(int var) noexcept { output_integer(var); return *this; } inline MaiPrinter& operator<<(long long var) noexcept { output_integer(var); return *this; } inline MaiPrinter& operator<<(char* str_p) noexcept { while (*str_p) putc_x(*(str_p++), fp_); return *this; } inline MaiPrinter& operator<<(const string& str) { const char* p = str.c_str(); const char* l = p + str.size(); while (p < l) putc_x(*p++, fp_); return *this; } template void join(IT begin, IT end, char sep = ' ') { for (bool b = 0; begin != end; ++begin, b = 1) b ? *this << sep << *begin : *this << *begin; } }; MaiScanner scanner(stdin); MaiPrinter printer(stdout); template //using T = ll; class SegmentTree { public: struct IdxVal { int index; T value; inline IdxVal(int _i = 0, const T& _v = T()) :index(_i), value(_v) { } inline void set(int i, const T& v) { index = i; value = v; } inline bool operator<(const T& t) const { return value < t; } inline bool operator==(const T& t) const { return value == t; } inline bool operator<(const IdxVal& iv) const { return value < iv.value || (value == iv.value && index < iv.index); } inline bool operator==(const IdxVal & iv) const { return index == iv.index && value == iv.value; } }; enum struct Cmd { None, Add, Flat }; struct Node { T sum, lazyValue; IdxVal max; Cmd lazyType; }; private: const int size_; vector leaf_data_; vector node_data_; T* leaf_; Node* node_; void _resize() { leaf_data_.resize(size_); node_data_.resize(size_ - 1); leaf_ = &leaf_data_[0]; node_ = &node_data_[0] - 1; } void _init() { for (int i = size_ - 1; 0 < i; --i) { int c = i << 1; if (size_ <= c) node_[i].max.set(c - size_, leaf_[c - size_]); else node_[i].max = node_[c].max; node_[i].lazyType = Cmd::None; node_[i].sum = node_[i].lazyValue = 0; } } public: inline void fill(T val) { std::fill(leaf_data_.begin(), leaf_data_.end(), val); _init(); } SegmentTree(int _n) : size_([](int _n) {int s = 8; while (s < _n) s <<= 1; return s; }(_n)) { _resize(); _init(); } SegmentTree(int _n, const T & _fillVal) : size_([](int _n) {int s = 8; while (s < _n) s <<= 1; return s; }(_n)) { _resize(); fill(_fillVal); } private: // lazyを適応する(子を呼ぶ前に呼ぶ) // width: ptrが担当するnodeの範囲の大きさ(ptr = 1 ならば size_) inline void _applyDown(int ptr, int width) { width >>= 1; //if (size_ <= ptr) return; if (node_[ptr].lazyType == Cmd::Add) { int c = ptr << 1; if (size_ <= c) { leaf_[c - size_] += node_[ptr].lazyValue; leaf_[c + 1 - size_] += node_[ptr].lazyValue; } else { node_[c].sum += node_[ptr].lazyValue * width; node_[c].max.value += node_[ptr].lazyValue; node_[c].lazyValue += node_[ptr].lazyValue; if (node_[c].lazyType == Cmd::None) node_[c].lazyType = Cmd::Add; node_[c + 1].sum += node_[ptr].lazyValue * width; node_[c + 1].max.value += node_[ptr].lazyValue; node_[c + 1].lazyValue += node_[ptr].lazyValue; if (node_[c + 1].lazyType == Cmd::None) node_[c + 1].lazyType = Cmd::Add; } node_[ptr].lazyType = Cmd::None; node_[ptr].lazyValue = 0; } else if (node_[ptr].lazyType == Cmd::Flat) { node_[ptr].lazyType = Cmd::None; int c = ptr << 1; if (size_ <= c) { leaf_[c - size_] = node_[ptr].lazyValue; leaf_[c + 1 - size_] = node_[ptr].lazyValue; } else { node_[c].sum = node_[ptr].lazyValue * width; node_[c].max.value = node_[ptr].lazyValue; node_[c].lazyValue += node_[ptr].lazyValue; node_[c].lazyType = Cmd::Flat; node_[c + 1].sum = node_[ptr].lazyValue * width; node_[c + 1].max.value = node_[ptr].lazyValue; node_[c + 1].lazyValue += node_[ptr].lazyValue; node_[c + 1].lazyType = Cmd::Flat; } node_[ptr].lazyType = Cmd::None; node_[ptr].lazyValue = 0; } } // lazyを適応する(子を呼んだ後に呼ぶ) inline void _applyUp(int ptr) { if (size_ <= ptr << 1) { int i = (ptr << 1) - size_; if (leaf_[i] < leaf_[i + 1]) node_[ptr].max.set(i + 1, leaf_[i + 1]); else node_[ptr].max.set(i, leaf_[i]); node_[ptr].sum = leaf_[i] + leaf_[i + 1]; } else { if (node_[(ptr << 1)].max.value < node_[(ptr << 1) + 1].max.value) node_[ptr].max = node_[(ptr << 1) + 1].max; else node_[ptr].max = node_[(ptr << 1)].max; node_[ptr].sum = node_[ptr << 1].sum + node_[(ptr << 1) + 1].sum; } } // _downward_applyDown(ptr1): leaf[ptr1]の値を正しくする. void _downward_applyDown(int ptr1, int width = 1) { if (1 < ptr1) _downward_applyDown(ptr1 >> 1, width << 1); _applyDown(ptr1, width); } void _setValueRange(int begin, int end, T val, int ptr, int rangebegin, int rangeend) { if (rangeend <= begin || end <= rangebegin) return; // note:範囲外 if (begin <= rangebegin && rangeend <= end) { if (size_ <= ptr) { leaf_[rangebegin] = val; } else { node_[ptr].sum = val * (rangeend - rangebegin); node_[ptr].max.value = val; node_[ptr].lazyType = Cmd::Flat; node_[ptr].lazyValue = val; } return; } _applyDown(ptr, rangeend - rangebegin); _setValueRange(begin, end, val, ptr << 1, rangebegin, (rangebegin + rangeend) >> 1); _setValueRange(begin, end, val, (ptr << 1) + 1, (rangebegin + rangeend) >> 1, rangeend); _applyUp(ptr); } void _addValueRange(int begin, int end, T val, int ptr, int rangebegin, int rangeend) { if (rangeend <= begin || end <= rangebegin) return; // note:範囲外 if (begin <= rangebegin && rangeend <= end) { if (size_ <= ptr) { leaf_[rangebegin] += val; } else { node_[ptr].sum += val * (rangeend - rangebegin); node_[ptr].max.value += val; node_[ptr].lazyValue += val; if (node_[ptr].lazyType == Cmd::None) node_[ptr].lazyType = Cmd::Add; } return; } _applyDown(ptr, rangeend - rangebegin); _addValueRange(begin, end, val, ptr << 1, rangebegin, (rangebegin + rangeend) >> 1); _addValueRange(begin, end, val, (ptr << 1) + 1, (rangebegin + rangeend) >> 1, rangeend); _applyUp(ptr); } T _getSumRange(int begin, int end, int ptr, int rangebegin, int rangeend) { if (rangeend <= begin || end <= rangebegin) return 0; // note:範囲外 if (begin <= rangebegin && rangeend <= end) { if (size_ <= ptr) return leaf_[rangebegin]; else return node_[ptr].sum; } _applyDown(ptr, rangeend - rangebegin); return _getSumRange(begin, end, ptr << 1, rangebegin, (rangebegin + rangeend) >> 1) + _getSumRange(begin, end, (ptr << 1) + 1, (rangebegin + rangeend) >> 1, rangeend); } IdxVal _getMaxRange(int begin, int end, int ptr, int rangebegin, int rangeend) { if (rangeend <= begin || end <= rangebegin) return IdxVal(-1); // note:範囲外 if (begin <= rangebegin && rangeend <= end) { if (size_ <= ptr) return IdxVal(rangebegin, leaf_[rangebegin]); else return node_[ptr].max; } _applyDown(ptr, rangeend - rangebegin); auto l = _getMaxRange(begin, end, ptr << 1, rangebegin, (rangebegin + rangeend) >> 1); auto r = _getMaxRange(begin, end, (ptr << 1) + 1, (rangebegin + rangeend) >> 1, rangeend); if (l.index == -1) return move(r); if (r.index == -1) return move(l); return l.value < r.value ? move(r) : move(l); } public: // [index] の値を求める inline T getValue(int index) { _downward_applyDown((index + size_) >> 1); return leaf_[index]; } // [index] の値を書き換える inline void setValue(int index, T val) { _downward_applyDown((index + size_) >> 1); T diff = val - leaf_[index]; leaf_[index] = val; for (int ptr = (index + size_); 1 < ptr;) { ptr >>= 1; node_[ptr].sum -= diff; _applyUp(ptr); } } // [index] の値に加算する inline void addValue(int index, T val) { _downward_applyDown((index + size_) >> 1); leaf_[index] += val; for (int ptr = (index + size_); 1 < ptr;) { ptr >>= 1; node_[ptr].sum += val; _applyUp(ptr); } } // 区間[begin,end)全てにvalをセットする inline void setValueRange(int begin, int end, T val) { _setValueRange(begin, end, val, 1, 0, size_); } // 区間[begin,end)に一様にvalを加算する inline void addValueRange(int begin, int end, T val) { _addValueRange(begin, end, val, 1, 0, size_); } // 区間[begin,end)の和を求める inline T getSumRange(int begin, int end) { return _getSumRange(begin, end, 1, 0, size_); } // 区間[begin,end)の最大値とその位置を求める inline IdxVal getMaxRange(int begin, int end) { return _getMaxRange(begin, end, 1, 0, size_); } }; int N, Q; int main() { scanner >> N >> Q; SegmentTree kakkoyosa(N); SegmentTree left(N); SegmentTree right(N); repeat(i, N) { int a; scanner >> a; kakkoyosa.setValue(i, a); left.setValue(i, i); right.setValue(i, i + 1); } repeat(_, Q) { int type, z; scanner >> type >> z; --z; if (type == 1) { int r1 = right.getValue(z); if (r1 > z + 1) continue; int l1 = left.getValue(z); int l2 = left.getValue(z+1); int r2 = right.getValue(z+1); right.setValueRange(l1, r1, r2); left.setValueRange(l2, r2, l1); } else if (type == 2) { int r1 = right.getValue(z); if (r1 == z + 1) continue; int l1 = left.getValue(z); right.setValueRange(l1, z + 1, z + 1); left.setValueRange(z + 1, r1, z + 1); } else if (type == 3) { kakkoyosa.addValue(z, 1); } else if (type == 4) { int l = left.getValue(z); int r = right.getValue(z); printer << kakkoyosa.getSumRange(l, r) << '\n'; } } return 0; }