Problem:
Problem I : RMQ
n
個の数字
a
0
,
a
1
, ... ,
a
n-1
と
q
が与えられる。
q
個のクエリーに対して適切な処理を行なって欲しい。
クエリーは以下の3種類の操作が存在する。
値のシフトを行う
l
と
r
のペアが与えられる。(
l
<
r
)
a
l
から
a
r
までの値を Circular Shiftさせる。
0 1 2 3 4 5 6 7 8 9
に対してl=2,r=5というクエリーが与えられたとする。
シフトを行った数字列は
0 1 5 2 3 4 6 7 8 9
となる。
最小値を求める
l
と
r
のペアが与えられる。(
l
≤
r
)
a
l
から
a
r
までの値の中で最小の値を求める。
値の更新
pos
と
val
のペアが与えられる。
a
pos
の値を
val
に更新する。
Input
入力は以下のフォーマットで与えられる。
n
q
a
0
a
1
.
.
.
a
n-1
x
1
y
1
z
1
x
2
y
2
z
2
.
.
.
x
q
y
q
z
q
x
i
= 0
なら、シフトのクエリーを表す。このとき、
l = y
i
,
r = z
i
とする。
x
i
= 1
なら、最小値を求めるクエリーを表す。このとき、
l = y
i
,
r = z
i
とする。
x
i
= 2
なら、値を更新するクエリーを表す。このとき、
pos = y
i
,
val = z
i
とする。
入力は以下の制約を満たす
1 ≤
n , q
≤ 200,000
0 ≤
a
i
≤ 10,000,000
値を更新するクエリーについて、0 ≤
val
≤ 10,000,000
Output
クエリーとして
x
i
= 1
が与えられたときに、答えの値を１行に出力せよ。
Sample Input 1
10 3
0
1
2
3
4
5
6
7
8
9
1 5 7
0 2 5
1 5 7
Sample Output 1
5
4
Sample Input 2
10 10
289383
930886
692777
636915
747793
238335
885386
760492
516649
641421
2 7 368690
1 3 6
0 2 6
1 1 8
0 2 9
2 2 665123
1 5 9
0 2 8
2 7 961393
1 1 2
Sample Output 2
238335
238335
238335
368690

Submitted solutions:

code_snippet: // Begin include: "../../template/template.hpp"
using namespace std;

// intrinstic
#include <immintrin.h>

#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cfenv>
#include <cfloat>
#include <chrono>
#include <cinttypes>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <fstream>
#include <functional>
#include <initializer_list>
#include <iomanip>
#include <ios>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <streambuf>
#include <string>
#include <tuple>
#include <type_traits>
#include <typeinfo>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

// utility
// Begin include: "util.hpp"
namespace yamada {
using ll = long long;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
using lld = long double;

template <typename T>
using V = vector<T>;
template <typename T>
using VV = vector<vector<T>>;
template <typename T>
using VVV = vector<vector<vector<T>>>;
template <typename T>
using VVVV = vector<vector<vector<vector<T>>>>;
using vl = vector<long long>;
using vd = V<double>;
using vs = V<string>;
using vvl = vector<vector<long long>>;
using vvvl = vector<vector<vector<long long>>>;
using vvvvl = vector<vector<vector<vector<long long>>>>;
template <typename T>
using minpq = priority_queue<T, vector<T>, greater<T>>;
template <typename T>
using maxpq = priority_queue<T, vector<T>, less<T>>;

template <typename T, typename U>
struct P : pair<T, U> {
	template <typename... Args>
	P(Args... args) : pair<T, U>(args...) {}

	using pair<T, U>::first;
	using pair<T, U>::second;

	P &operator+=(const P &r) {
		first += r.first;
		second += r.second;
		return *this;
	}
	P &operator-=(const P &r) {
		first -= r.first;
		second -= r.second;
		return *this;
	}
	P &operator*=(const P &r) {
		first *= r.first;
		second *= r.second;
		return *this;
	}
	template <typename S>
	P &operator*=(const S &r) {
		first *= r, second *= r;
		return *this;
	}
	P operator+(const P &r) const { return P(*this) += r; }
	P operator-(const P &r) const { return P(*this) -= r; }
	P operator*(const P &r) const { return P(*this) *= r; }
	template <typename S>
	P operator*(const S &r) const {
		return P(*this) *= r;
	}
	P operator-() const { return P{-first, -second}; }
};

using pl = P<ll, ll>;
using vp = V<pl>;
using vvp = VV<pl>;

constexpr int inf = 1001001001;
constexpr long long infLL = 4004004004004004004LL;

template <typename T, typename U>
inline bool amin(T &x, U y) { return (y < x) ? (x = y, true) : false; }
template <typename T, typename U>
inline bool amax(T &x, U y) { return (x < y) ? (x = y, true) : false; }

template <typename T>
inline T Max(const vector<T> &v) { return *max_element(begin(v), end(v)); }
template <typename T>
inline T Min(const vector<T> &v) { return *min_element(begin(v), end(v)); }
template <typename T>
inline long long Sum(const vector<T> &v) { return accumulate(begin(v), end(v), T(0)); }

template <typename T>
int lb(const vector<T> &v, const T &a) { return lower_bound(begin(v), end(v), a) - begin(v); }
template <typename T>
int ub(const vector<T> &v, const T &a) { return upper_bound(begin(v), end(v), a) - begin(v); }

constexpr long long TEN(int n) {
	long long ret = 1, x = 10;
	for (; n; x *= x, n >>= 1) ret *= (n & 1 ? x : 1);
	return ret;
}

template <typename T>
vector<T> mkrui(const vector<T> &v, bool rev = false) {
	vector<T> ret(v.size() + 1);
	if (rev) {
		for (int i = int(v.size()) - 1; i >= 0; i--) ret[i] = v[i] + ret[i + 1];
	} else {
		for (int i = 0; i < int(v.size()); i++) ret[i + 1] = ret[i] + v[i];
	}
	return ret;
};

template <typename T>
vector<T> mkuni(const vector<T> &v) {
	vector<T> ret(v);
	sort(ret.begin(), ret.end());
	ret.erase(unique(ret.begin(), ret.end()), ret.end());
	return ret;
}

template <typename F>
vector<int> mkord(int N, F f) {
	vector<int> ord(N);
	iota(begin(ord), end(ord), 0);
	sort(begin(ord), end(ord), f);
	return ord;
}

template <typename T>
vector<int> mkinv(vector<T> &v) {
	int max_val = *max_element(begin(v), end(v));
	vector<int> inv(max_val + 1, -1);
	for (int i = 0; i < (int)v.size(); i++) inv[v[i]] = i;
	return inv;
}

vector<int> mkiota(int n) {
	vector<int> ret(n);
	iota(begin(ret), end(ret), 0);
	return ret;
}

template <typename T>
T mkrev(const T &v) {
	T w{v};
	reverse(begin(w), end(w));
	return w;
}

template <typename T>
bool nxp(T &v) { return next_permutation(begin(v), end(v)); }

// 返り値の型は入力の T に依存
// i 要素目 : [0, a[i])
template <typename T>
vector<vector<T>> product(const vector<T> &a) {
	vector<vector<T>> ret;
	vector<T> v;
	auto dfs = [&](auto rc, int i) -> void {
		if (i == (int)a.size()) {
			ret.push_back(v);
			return;
		}
		for (int j = 0; j < a[i]; j++) v.push_back(j), rc(rc, i + 1), v.pop_back();
	};
	dfs(dfs, 0);
	return ret;
}

template <typename T, typename U>
vector<U> Digit(T a, const U &x, int siz = -1) {
	vector<U> ret;
	while (a > 0) {
		ret.emplace_back(a % x);
		a /= x;
	}
	if (siz >= 0) while ((int)ret.size() < siz) ret.emplace_back(0);
	return ret;
}

// F : function(void(T&)), mod を取る操作
// T : 整数型のときはオーバーフローに注意する
template <typename T>
T Power(T a, long long n, const T &I, const function<void(T &)> &f) {
	T res = I;
	for (; n; f(a = a * a), n >>= 1) {
		if (n & 1) f(res = res * a);
	}
	return res;
}
// T : 整数型のときはオーバーフローに注意する
template <typename T>
T Power(T a, long long n, const T &I = T{1}) {
	return Power(a, n, I, function<void(T &)>{[](T &) -> void {}});
}

template <typename T>
T Rev(const T &v) {
	T res = v;
	reverse(begin(res), end(res));
	return res;
}

template <typename T>
vector<T> Transpose(const vector<T> &v) {
	using U = typename T::value_type;
	if(v.empty()) return {};
	int H = v.size(), W = v[0].size();
	vector res(W, T(H, U{}));
	for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) res[j][i] = v[i][j];
	return res;
}

template <typename T>
vector<T> Rotate(const vector<T> &v, int clockwise = true) {
	using U = typename T::value_type;
	int H = v.size(), W = v[0].size();
	vector res(W, T(H, U{}));
	for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) {
		if (clockwise) res[W - 1 - j][i] = v[i][j];
		else res[j][H - 1 - i] = v[i][j];
	}
	return res;
}

template <typename T, typename F>
T bisect(T ok, T bad, F pred) {
	if (ok == bad) return ok;
	if (!pred(ok)) return ok; 
	while (bad - ok > 1) { T mid = ok + (bad - ok) / 2; (pred(mid) ? ok : bad) = mid; } 
	return bad;
}

template <typename T, typename F>
T bisect_double(T ok, T bad, F pred, int iter = 100) {
	if (ok == bad) return ok;
	if (!pred(ok)) return ok; 
	while (iter--) { T mid = ok + (bad - ok) / 2; (pred(mid) ? ok : bad) = mid; } 
	return bad;
}

template <typename T>
bool inLR(T L, T x, T R){ return (L <= x && x < R); }

bool YESNO(bool b) { cout << (b ? "YES\n" : "NO\n"); return b; }
bool YesNo(bool b) { cout << (b ? "Yes\n" : "No\n"); return b; }

template <typename mint>
void mout(mint a, int M = 100) {
	if (a == 0) { cout << 0 << "\n"; return; }
	for (int i = 0; i <= M; i++) for (int j = 1; j <= M; j++) {
		mint val = (mint)i / j;
		if (val == a) {
			if (j == 1) cout << i << "\n";
			else cout << i << "/" << j << "\n";
			return;
		}
		else if (val == -a) {
			if (j == 1) cout << -i << "\n";
			else cout << -i << "/" << j << "\n";
			return;
		}
	}
	cout << "NF\n";
}

template <typename mint>
void mout(std::vector<mint> A, int M = 100) {
	int N = A.size();
	for (int pos = 0; pos < N; pos++) {
		if (A[pos] == 0) { cout << 0 << (pos == N - 1 ? "\n" : " "); continue; }
		bool found = false;
		for (int i = 0; i <= M; i++) {
			for (int j = 1; j <= M; j++) {
				mint val = (mint)i / j;
				if (val == A[pos]) {
					if (j == 1) cout << i << (pos == N - 1 ? "\n" : " ");
					else cout << i << "/" << j << (pos == N - 1 ? "\n" : " ");
					found = true;
					break;
				}
				else if (val == -A[pos]) {
					if (j == 1) cout << -i << (pos == N - 1 ? "\n" : " ");
					else cout << -i << "/" << j << (pos == N - 1 ? "\n" : " ");
					found = true;
					break;
				}
			}
			if (found) break;
		}
		if (!found) cout << "NF" << (pos == N - 1 ? "\n" : " ");
	}
}

bool is_square(uint64_t n) {
	if (n < 2) return true;
	uint64_t r = static_cast<uint64_t>(sqrtl(static_cast<long double>(n)));
	if (r * r == n) return true;
	++r;
	return r * r == n;
}

template <typename T>
struct CumulativeSum {
	std::vector<T> S;
	CumulativeSum(std::vector<T> &A) {
		int N = A.size();
		S.resize(N + 1);
		for (int i = 0; i < N; i++) S[i + 1] = S[i] + A[i];
	}

	T query(int l, int r) { return (l <= r ? S[r] - S[l] : (T)0); }
	T get_val(int i) { return S[i + 1] - S[i]; }
};

template <typename T>
T extgcd(T a, T b, T &x, T &y) {
	T d = a;
	if(b != 0) {
		d = extgcd(b, a % b, y, x);
		y -= (a / b) * x;
	}
	else x = 1, y = 0;
	return d;
}

// floor(sqrt(x))
long long isqrt (long long x) {
	long long y = sqrt(x);
	while (y * y > x) y--;
	while ((y + 1) * (y + 1) <= x) y++;
	return y;
}

template <typename T>
T Floor(T a, T b) { return a / b - (a % b && (a ^ b) < 0); }
template <typename T>
T Ceil(T a, T b) { return a / b + (a % b && (a ^ b) >= 0); }

} // namespace yamada

// End include: "util.hpp"

// bit operation
// Begin include: "bitop.hpp"
namespace yamada {
__attribute__((target("popcnt"))) inline int popcnt(const u64 &a) {
  return __builtin_popcountll(a);
}
inline int lsb(const u64 &a) { return a ? __builtin_ctzll(a) : 64; }
inline int ctz(const u64 &a) { return a ? __builtin_ctzll(a) : 64; }
inline int msb(const u64 &a) { return a ? 63 - __builtin_clzll(a) : -1; }
template <typename T>
inline int gbit(const T &a, int i) {
  return (a >> i) & 1;
}
template <typename T>
inline void sbit(T &a, int i, bool b) {
  if (gbit(a, i) != b) a ^= T(1) << i;
}
constexpr long long PW(int n) { return 1LL << n; }
constexpr long long MSK(int n) { return (1LL << n) - 1; }
}  // namespace yamada
// End include: "bitop.hpp"

// inout
// Begin include: "inout.hpp"
namespace yamada {

template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
	os << p.first << " " << p.second;
	return os;
}
template <typename T, typename U>
istream &operator>>(istream &is, pair<T, U> &p) {
	is >> p.first >> p.second;
	return is;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v) {
	int s = (int)v.size();
	for (int i = 0; i < s; i++) os << (i ? " " : "") << v[i];
	return os;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &v) {
	for (auto &x : v) is >> x;
	return is;
}

istream &operator>>(istream &is, __int128_t &x) {
	string S;
	is >> S;
	x = 0;
	int flag = 0;
	for (auto &c : S) {
		if (c == '-') {
			flag = true;
			continue;
		}
		x *= 10;
		x += c - '0';
	}
	if (flag) x = -x;
	return is;
}

istream &operator>>(istream &is, __uint128_t &x) {
	string S;
	is >> S;
	x = 0;
	for (auto &c : S) {
		x *= 10;
		x += c - '0';
	}
	return is;
}

ostream &operator<<(ostream &os, __int128_t x) {
	if (x == 0) return os << 0;
	if (x < 0) os << '-', x = -x;
	string S;
	while (x) S.push_back('0' + x % 10), x /= 10;
	reverse(begin(S), end(S));
	return os << S;
}
ostream &operator<<(ostream &os, __uint128_t x) {
	if (x == 0) return os << 0;
	string S;
	while (x) S.push_back('0' + x % 10), x /= 10;
	reverse(begin(S), end(S));
	return os << S;
}

void in() {}
template <typename T, class... U>
void in(T &t, U &...u) {
	cin >> t;
	in(u...);
}

void out() { cout << "\n"; }
template <typename T, class... U, char sep = ' '>
void out(const T &t, const U &...u) {
	cout << t;
	if (sizeof...(u)) cout << sep;
	out(u...);
}

struct IoSetupYamada {
	IoSetupYamada() {
		cin.tie(nullptr);
		ios::sync_with_stdio(false);
		cout << fixed << setprecision(15);
		cerr << fixed << setprecision(7);
	}
} iosetupyamada;

}  // namespace yamada
// End include: "inout.hpp"

// macro
// Begin include: "macro.hpp"
#define each(x, v) for (auto&& x : v)
#define each2(x, y, v) for (auto&& [x, y] : v)
#define each3(x, y, z, v) for (auto&& [x, y, z] : v)
#define all(v) (v).begin(), (v).end()

#define rep1(a) for (long long _ = 0; _ < (long long)(a); ++_)
#define rep2(i, a) for (long long i = 0; i < (long long)(a); ++i)
#define rep3(i, a, b) for (long long i = a; i < (long long)(b); ++i)
#define rep4(i, a, b, c) for (long long i = a; i < (long long)(b); i += c)
#define overload4(a, b, c, d, e, ...) e
#define rep(...) overload4(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__)

#define rep1r(a) for (long long i = (long long)(a)-1; i >= 0LL; --i)
#define rep2r(i, a) for (long long i = (long long)(a)-1; i >= 0LL; --i)
#define rep3r(i, a, b) for (long long i = (long long)(b)-1; i >= (long long)(a); --i)
#define overload3(a, b, c, d, ...) d
#define repr(...) overload3(__VA_ARGS__, rep3r, rep2r, rep1r)(__VA_ARGS__)

#define eb emplace_back
#define mkp make_pair
#define mkt make_tuple
#define fi first
#define se second

#define vv(type, name, h, ...)  \
	vector<vector<type> > name(h, vector<type>(__VA_ARGS__))
#define vvv(type, name, h, w, ...) \
	vector<vector<vector<type>>> name( \
			h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)  \
	vector<vector<vector<vector<type>>>> name( \
			a, vector<vector<vector<type>>>( \
				b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))

#define ini(...)   \
	int __VA_ARGS__; \
	in(__VA_ARGS__)
#define inl(...)         \
	long long __VA_ARGS__; \
	in(__VA_ARGS__)
#define ins(...)      \
	string __VA_ARGS__; \
	in(__VA_ARGS__)
#define in2(s, t)                           \
	for (int i = 0; i < (int)s.size(); i++) { \
		in(s[i], t[i]);                         \
	}
#define in3(s, t, u)                        \
	for (int i = 0; i < (int)s.size(); i++) { \
		in(s[i], t[i], u[i]);                   \
	}
#define in4(s, t, u, v)                     \
	for (int i = 0; i < (int)s.size(); i++) { \
		in(s[i], t[i], u[i], v[i]);             \
	}
#define die(...)             \
	do {                       \
		yamada::out(__VA_ARGS__);\
		return;                  \
	} while (0)
// End include: "macro.hpp"

namespace yamada {
void solve();
}
int main() { yamada::solve(); }
// End include: "../../template/template.hpp"
// Begin include: "../../rbst/lazy-reversible-rbst.hpp"

// Begin include: "rbst-base.hpp"

// RBSTそのものではなく、RBSTを操作する関数の集合体
template <typename Node>
struct RBSTBase {
	using Ptr = Node *;
	template <typename... Args>
	inline Ptr my_new(Args... args) { return new Node(args...); }
	inline void my_del(Ptr t) { delete t; }
	inline Ptr make_tree() const { return nullptr; }

	// メモリリーク回避用（遅い）
	
	/* using Ptr = shared_ptr<Node>; */
	/* template <typename... Args> */
	/* inline Ptr my_new(Args... args) { */
	/* 	return make_shared<Node>(args...); */
	/* } */
	/* inline void my_del(Ptr t) {} */
	/* Ptr make_tree() {return Ptr();} */

	int size(Ptr t) const { return count(t); }

	Ptr merge(Ptr l, Ptr r) {
		if (!l || !r) return l ? l : r;
		if (int((rng() * (l->cnt + r->cnt)) >> 32) < l->cnt) {
			push(l);
			l->r = merge(l->r, r);
			return update(l);
		}
		else {
			push(r);
			r->l = merge(l, r->l);
			return update(r);
		}
	}

	pair<Ptr, Ptr> split(Ptr t, int k) {
		if (!t) return {nullptr, nullptr};
		push(t);
		if (k <= count(t->l)) {
			auto s = split(t->l, k);
			t->l = s.second;
			return {s.first, update(t)};
		}
		else {
			auto s = split(t->r, k - count(t->l) - 1);
			t->r = s.first;
			return {update(t), s.second};
		}
	}

	Ptr build(int l, int r, const vector<decltype(Node::key)> &v) {
		if (l + 1 == r) return my_new(v[l]);
		int m = (l + r) >> 1;
		Ptr pm = my_new(v[m]);
		if (l < m) pm->l = build(l, m, v);
		if (m + 1 < r) pm->r = build(m + 1, r, v);
		return update(pm);
	}

	Ptr build(const vector<decltype(Node::key)> &v) {
		return build(0, (int)v.size(), v);
	}

	template <typename... Args>
	void insert(Ptr &t, int k, const Args &... args) {
		auto x = split(t, k);
		t = merge(merge(x.first, my_new(args...)), x.second);
	}

	decltype(Node::key) erase(Ptr &t, int k) {
		auto x = split(t, k);
		auto y = split(x.second, 1);
		auto ret = y.first->key;
		my_del(y.first);
		t = merge(x.first, y.second);
		return ret;
	}

	// 最後に check(s) が成り立つところまでを左としてsplit
	template <typename F>
	pair<Ptr, Ptr> split_max_right(Ptr& root, const F &check) {
		if (!root) return {nullptr, nullptr};
		push(root);
		if (check(root)) {
			auto [u0, u1] = split_max_right(root->r, check);
			root->r = u0;
			update(root);
			return {root, u1};
		}
		else {
			auto [u0, u1] = split_max_right(root->l, check);
			root->l = u1;
			update(root);
			return {u0, root};
		}
	}

	vector<Ptr> enumerate(Ptr& root) {
		if (!root) return vector<Ptr>();
		vector<Ptr> ans(root->cnt);
		int ansi = 0;
		auto dfs = [&](auto&& self, Ptr u)->void{
			if (!u) return;
			update(u);
			self(self, u->l);
			ans[ansi++] = u;
			self(self, u->r);
		}; dfs(dfs, root);
		return ans;
	}

	protected:
	static uint64_t rng() {
		static uint64_t x_ = 88172645463325252ULL;
		return x_ ^= x_ << 7, x_ ^= x_ >> 9, x_ & 0xFFFFFFFFull;
	}

	inline int count(const Ptr t) const { return t ? t->cnt : 0; }

	virtual void push(Ptr) = 0;

	virtual Ptr update(Ptr) = 0;
};

/**
 * @brief 乱択平衡二分木(基底クラス)
 */
// End include: "rbst-base.hpp"

// 限界高速化がしたいなら遅延伝播機能、sum機能、反転機能あたり削れたら削る
template <typename T, typename E>
struct LazyReversibleRBSTNode {
	typename RBSTBase<LazyReversibleRBSTNode>::Ptr l, r;
	T key, sum;
	E lazy;
	int cnt;
	bool rev;

	LazyReversibleRBSTNode(const T &t = T(), const E &e = E())
		: l(), r(), key(t), sum(t), lazy(e), cnt(1), rev(false) {}
};

template <typename T, typename E, T (*f)(T, T), T (*g)(T, E), E (*h)(E, E), T (*ts)(T)>
struct LazyReversibleRBST : RBSTBase<LazyReversibleRBSTNode<T, E>> {
	using Node = LazyReversibleRBSTNode<T, E>;
	using base = RBSTBase<LazyReversibleRBSTNode<T, E>>;
	using base::merge;
	using base::split;
	using typename base::Ptr;

	LazyReversibleRBST() = default;

	void toggle(Ptr t) {
		if(!t) return;
		swap(t->l, t->r);
		t->sum = ts(t->sum);
		t->rev ^= true;
	}

	T fold(Ptr &t, int a, int b) {
		auto x = split(t, a);
		auto y = split(x.second, b - a);
		auto ret = sum(y.first);
		t = merge(x.first, merge(y.first, y.second));
		return ret;
	}
	
	T fold(Ptr &t) { return t ? t->sum : T(); }

	void reverse(Ptr &t, int a, int b) {
		auto x = split(t, a);
		auto y = split(x.second, b - a);
		toggle(y.first);
		t = merge(x.first, merge(y.first, y.second));
	}

	void apply(Ptr &t, int a, int b, const E &e) {
		auto x = split(t, a);
		auto y = split(x.second, b - a);
		propagate(y.first, e);
		t = merge(x.first, merge(y.first, y.second));
	}

	void apply(Ptr &t, const E &e) { if (t) propagate(t, e); }

	protected:
	inline T sum(const Ptr t) const { return t ? t->sum : T(); }

	Ptr update(Ptr t) override {
		push(t);
		t->cnt = 1;
		t->sum = t->key;
		if (t->l) t->cnt += t->l->cnt, t->sum = f(t->l->sum, t->sum);
		if (t->r) t->cnt += t->r->cnt, t->sum = f(t->sum, t->r->sum);
		return t;
	}

	void push(Ptr t) override {
		if (t->rev) {
			if (t->l) toggle(t->l);
			if (t->r) toggle(t->r);
			t->rev = false;
		}
		if (t->lazy != E()) {
			if (t->l) propagate(t->l, t->lazy);
			if (t->r) propagate(t->r, t->lazy);
			t->lazy = E();
		}
	}

	void propagate(Ptr t, const E &x) {
		t->lazy = h(t->lazy, x);
		t->key = g(t->key, x);
		t->sum = g(t->sum, x);
	}
};
// End include: "../../rbst/lazy-reversible-rbst.hpp"
using namespace yamada;

using T=ll;
using E=bool;
T F(T a,T b){return min(a,b);}
T G(T a,E e){return a;}
E H(E e,E f){return e;}
T TS(T a){return a;}

void yamada::solve()
{
	inl(N,Q);
	vl A(N); in(A);
	LazyReversibleRBST<T,E,F,G,H,TS> st;
	auto root=st.build(A);

	while(Q--){
		inl(op);
		if(op==0){
			inl(i,j);
			auto val=st.erase(root,j);
			st.insert(root,i,val);
		}
		else if(op==1){
			inl(l,r); ++r;
			out(st.fold(root,l,r));
		}
		else{
			inl(pos,val);
			st.erase(root,pos);
			st.insert(root,pos,val);
		}
	}
}
accuracy: 1
time_ms: 320
memory_kb: 17076
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long;
using pll = pair<ll, ll>;
#define vc vector
using vl = vc<ll>;

#define ov(a, b, c, name, ...) name
#define rep2(i, l, r) for (ll i = (l); i < ll(r); i++)
#define rep1(i, n) rep2(i, 0, n)
#define rep(...) ov(__VA_ARGS__, rep2, rep1)(__VA_ARGS__)
#define fec(...) for (const auto &__VA_ARGS__)
#define per(i, a, b) for (ll i = ll(a) - 1; i >= ll(b); i--)

#define ALL(x) begin(x), end(x)
#define SZ(x) (ll) size(x)
#define LB(v, x) (lower_bound(ALL(v), x) - begin(v))
#define eb emplace_back

const ll INF = ll(4e18) + 100;

#ifdef LOCAL
#define local(...) __VA_ARGS__
#else
#define local(...)
#endif

template <class S, auto op, auto e>
struct RBST
{
  inline int rnd()
  {
    static int x = 740318, y = 79431, z = 470138, w = 391731;
    int t = x ^ (x << 11);
    x = y, y = z, z = w;
    return w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
  }
  struct Node
  {
    Node *l, *r;
    int cnt;
    S x, sum;
    Node() = default;
    Node(S x) : l(0), r(0), cnt(1), x(x), sum(x) {}
  };
  using P = Node *;
  vc<Node> pool;
  int ptr = 0;
  inline P alloc(S v)
  {
    if (SZ(pool) == ptr)
      pool.resize(pool.size() * 2);
    return &(pool[ptr++] = Node(v));
  }
  RBST(int n) : pool(n) {}
  int cnt(P t) { return t ? t->cnt : 0; }
  S sum(P t) { return t ? t->sum : e(); }
  P update(P t)
  {
    t->cnt = cnt(t->l) + cnt(t->r) + 1;
    t->sum = op(op(sum(t->l), t->x), sum(t->r));
    return t;
  }
  P merge(P l, P r)
  {
    if (!l or !r)
      return l ? l : r;
    if (rnd() % (cnt(l) + cnt(r)) < cnt(l))
    {
      l->r = merge(l->r, r);
      return update(l);
    }
    r->l = merge(l, r->l);
    return update(r);
  }
  // t を [0, k) と [k, |t|) に分割
  pair<P, P> split(P t, int k)
  {
    if (!t)
      return {t, t};
    if (k <= cnt(t->l))
    {
      auto [l, r] = split(t->l, k);
      t->l = r;
      return {l, update(t)};
    }
    auto [l, r] = split(t->r, k - cnt(t->l) - 1);
    t->r = l;
    return {update(t), r};
  }
  // t の k 番目に v を挿入
  void insert(P &t, int k, S v)
  {
    auto [l, r] = split(t, k);
    t = merge(merge(l, alloc(v)), r);
  }
  // 削除は split と merge を組み合わせる
  // 区間クエリは split で切り出して sum を取得して merge で戻す
  // 初期化の使用例:
  // RBST<S, op, e>::P root = nullptr;
  // rep(i, A.size()) rbst.insert(root, i, A.at(i));
};

ll op(ll a, ll b) { return min(a, b); }
ll e() { return INF; }

int main()
{
#ifndef LOCAL
  cin.tie(0)->sync_with_stdio(0);
#endif

  local(while (true))
  {
    ll N, Q;
    cin >> N >> Q;
    vc<ll> A(N);
    rep(i, N) cin >> A.at(i);

    RBST<ll, op, e> rbst(N + Q);
    RBST<ll, op, e>::P root = nullptr;
    rep(i, N) rbst.insert(root, i, A.at(i));
    rep(_, Q)
    {
      ll t;
      cin >> t;
      if (t == 0)
      {
        ll L, R;
        cin >> L >> R;
        auto [xyr, z] = rbst.split(root, R + 1);
        auto [xy, r] = rbst.split(xyr, R);
        auto [x, y] = rbst.split(xy, L);
        root = rbst.merge(rbst.merge(rbst.merge(x, r), y), z);
      }
      else if (t == 1)
      {
        ll L, R;
        cin >> L >> R;
        R++;
        auto [xy, z] = rbst.split(root, R);
        auto [x, y] = rbst.split(xy, L);
        cout << rbst.sum(y) << "\n";
        root = rbst.merge(rbst.merge(x, y), z);
      }
      else if (t == 2)
      {
        ll K, V;
        cin >> K >> V;
        auto [xk, y] = rbst.split(root, K + 1);
        auto [x, k] = rbst.split(xk, K);
        root = rbst.merge(rbst.merge(x, rbst.alloc(V)), y);
      }
    }
  }
}
accuracy: 1
time_ms: 280
memory_kb: 20300
final_rank: 17

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long;
using pll = pair<ll, ll>;
#define vc vector
using vl = vc<ll>;

#define ov(a, b, c, name, ...) name
#define rep2(i, l, r) for (ll i = (l); i < ll(r); i++)
#define rep1(i, n) rep2(i, 0, n)
#define rep(...) ov(__VA_ARGS__, rep2, rep1)(__VA_ARGS__)
#define fec(...) for (const auto &__VA_ARGS__)
#define per(i, a, b) for (ll i = ll(a) - 1; i >= ll(b); i--)

#define ALL(x) begin(x), end(x)
#define SZ(x) (ll) size(x)
#define LB(v, x) (lower_bound(ALL(v), x) - begin(v))
#define eb emplace_back

const ll INF = ll(4e18) + 100;

#ifdef LOCAL
#define local(...) __VA_ARGS__
#else
#define local(...)
#endif

template <class S, auto op, auto e>
struct RBST
{
  inline int rnd()
  {
    static int x = 740318, y = 79431, z = 470138, w = 391731;
    int t = x ^ (x << 11);
    x = y, y = z, z = w;
    return w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
  }
  struct Node
  {
    Node *l, *r;
    int cnt;
    S x, sum;
    Node() = default;
    Node(S x) : l(0), r(0), cnt(1), x(x), sum(x) {}
  };
  using P = Node *;
  vc<Node> pool;
  int ptr = 0;
  inline P alloc(S v)
  {
    if (SZ(pool) == ptr)
      pool.resize(pool.size() * 2);
    return &(pool[ptr++] = Node(v));
  }
  RBST(int n) : pool(n) {}
  int cnt(P t) { return t ? t->cnt : 0; }
  S sum(P t) { return t ? t->sum : e(); }
  P update(P t)
  {
    t->cnt = cnt(t->l) + cnt(t->r) + 1;
    t->sum = op(op(sum(t->l), t->x), sum(t->r));
    return t;
  }
  P merge(P l, P r)
  {
    if (!l or !r)
      return l ? l : r;
    if (rnd() % (cnt(l) + cnt(r)) < cnt(l))
    {
      l->r = merge(l->r, r);
      return update(l);
    }
    r->l = merge(l, r->l);
    return update(r);
  }
  // t を [0, k) と [k, |t|) に分割
  pair<P, P> split(P t, int k)
  {
    if (!t)
      return {t, t};
    if (k <= cnt(t->l))
    {
      auto [l, r] = split(t->l, k);
      t->l = r;
      return {l, update(t)};
    }
    auto [l, r] = split(t->r, k - cnt(t->l) - 1);
    t->r = l;
    return {update(t), r};
  }
  // t の k 番目に v を挿入
  void insert(P &t, int k, S v)
  {
    auto [l, r] = split(t, k);
    t = merge(merge(l, alloc(v)), r);
  }
  // 削除は split と merge を組み合わせる
  // 区間クエリは split で切り出して sum を取得して merge で戻す
  // 初期化の使用例:
  // RBST<S, op, e>::P root = nullptr;
  // rep(i, A.size()) rbst.insert(root, i, A.at(i));
};

ll op(ll a, ll b) { return min(a, b); }
ll e() { return INF; }

int main()
{
  cin.tie(0)->sync_with_stdio(0);

  ll N, Q;
  cin >> N >> Q;
  vc<ll> A(N);
  rep(i, N) cin >> A.at(i);

  RBST<ll, op, e> rbst(N + Q);
  RBST<ll, op, e>::P root = nullptr;
  rep(i, N) rbst.insert(root, i, A.at(i));

  rep(_, Q)
  {
    ll t;
    cin >> t;
    if (t == 0) {
      ll L, R;
      cin >> L >> R;
      if (L >= R) continue;
      auto [xyr, z] = rbst.split(root, R + 1);
      auto [xy, r_node] = rbst.split(xyr, R);
      auto [x, y] = rbst.split(xy, L);
      root = rbst.merge(rbst.merge(x, r_node), rbst.merge(y, z));
    } else if (t == 1) {
      ll L, R;
      cin >> L >> R;
      auto [xy, z] = rbst.split(root, R + 1);
      auto [x, y] = rbst.split(xy, L);
      cout << rbst.sum(y) << "\n";
      root = rbst.merge(rbst.merge(x, y), z);
    } else if (t == 2) {
      ll K, V;
      cin >> K >> V;
      auto [x, y_and_z] = rbst.split(root, K);
      auto [y, z] = rbst.split(y_and_z, 1);
      root = rbst.merge(rbst.merge(x, rbst.alloc(V)), z);
    }
  }
}
accuracy: 1
time_ms: 280
memory_kb: 20248
final_rank: 16

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define fast ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define endl '\n'
#define ll long long

enum {
	NOTFOUND = 0xFFFFFFFFFFFFFFFFLLU
};

uint64_t NODE_NO = 0;

class Node {
public:
	uint64_t no;
	uint64_t num;
	uint64_t ones;
	Node *left;
	Node *right;
	int64_t balance;
	uint64_t bits;
	uint64_t bits_size;

	bool is_leaf;

	Node(uint64_t bits, uint64_t bits_size, bool is_leaf) : no(NODE_NO++), num(0), ones(0), bits(bits), bits_size(bits_size), is_leaf(is_leaf), left(nullptr), right(nullptr), balance(0) {}

	bool is_valid_node() {
		if (is_leaf) {
			if (num != 0) { return false; }
			if (ones != 0) { return false; }
			if (left != nullptr) { return false; }
			if (right != nullptr) { return false; }
		}
		else {
			if (num == 0) { return false; }
			if (left == nullptr) { return false; }
			if (right == nullptr) { return false; }
			if (bits != 0) { return false; }
			if (bits_size != 0) { return false; }
			if (ones > num) {return false; }
		}
		return true;
	}

	string info() {
		string str = "No:" + to_string(this->no) + "\n";
		if (is_leaf) {
			str += "size:" + to_string(this->bits_size) + "\n";
			for (int i = 0; i < bits_size; ++i) {
				str += to_string((bits >> (uint64_t)i) & (uint64_t)1);
			}
		}
		else {
			str += "num:" + to_string(this->num) + " ones:" + to_string(this->ones) + "\n";
		}

		return str;
	}
};

class DynamicBitVector {
public:
	Node *root;
	uint64_t size;
	uint64_t num_one;
	const uint64_t bits_size_limit = 32;

	DynamicBitVector(): root(nullptr), size(0), num_one(0) {}

	DynamicBitVector(vector<uint64_t> &v): root(nullptr), size(0), num_one(0) {
		if (v.size() == 0) {
			return;
		}

		deque<pair<Node*, uint64_t>> leaves;
		for (int i = 0; i < v.size(); i += this->bits_size_limit) {
			uint64_t bits = 0;
			const uint64_t bits_size = min(this->bits_size_limit, (uint64_t)v.size() - i);
			for (int j = 0; j < bits_size; ++j) {
				assert(v[i + j] == 0 or v[i + j] == 1);
				if (v[i + j] == 1) {
					bits |= (uint64_t)1 << j;
				}
			}

			leaves.emplace_back(make_pair(new Node(bits, bits_size, true), bits_size));
		}


		deque<tuple<Node*, uint64_t, uint64_t, uint64_t>> nodes;
		while (not leaves.empty()) {
			const auto node = leaves.front().first;
			const auto bits_size = leaves.front().second;
			leaves.pop_front();
			nodes.emplace_back(make_tuple(node, bits_size, popCount(node->bits), 0));
		}

		while (nodes.size() > 1) {

			deque<tuple<Node*, uint64_t, uint64_t, uint64_t>> next_nodes;
			while (not nodes.empty()) {

				if (nodes.size() == 1) {
					nodes.push_front(next_nodes.back());
					next_nodes.pop_back();
				}

				Node *left_node;
				uint64_t left_num, left_ones, left_height;
				tie(left_node, left_num, left_ones, left_height) = nodes.front(); nodes.pop_front();

				Node *right_node;
				uint64_t right_num, right_ones, right_height;
				tie(right_node, right_num, right_ones, right_height) = nodes.front(); nodes.pop_front();

				const auto internal_node = new Node(0, 0, false);
				internal_node->num = left_num;
				internal_node->ones = left_ones;
				internal_node->left = left_node;
				internal_node->right = right_node;
				internal_node->balance = right_height - left_height;

				next_nodes.emplace_back(make_tuple(internal_node, left_num + right_num, left_ones + right_ones, max(left_height, right_height) + 1));
			}

			nodes = next_nodes;
		}

		uint64_t height;
		tie(this->root, this->size, this->num_one, height) = nodes.front(); nodes.pop_front();
		assert(this->size == v.size());
	}


	uint64_t access(uint64_t pos) {
		assert(pos < this->size);

		return access(this->root, pos);
	}


	uint64_t rank(uint64_t bit, uint64_t pos) {
		assert(bit == 0 or bit == 1);
		assert(pos <= this->size);

		if (bit) {
			return rank1(this->root, pos, 0);
		}
		else {
			return pos - rank1(this->root, pos, 0);
		}
	}


	uint64_t select(uint64_t bit, uint64_t rank) {
		assert(bit == 0 or bit == 1);
		assert(rank > 0);

		if (bit == 0 and rank > this->size - this-> num_one) { return NOTFOUND; }
		if (bit == 1 and rank > this-> num_one)              { return NOTFOUND; }

		if (bit) {
			return select1(this->root, 0, rank);
		}
		else {
			return select0(this->root, 0, rank);
		}
	}


	void insert(uint64_t pos, uint64_t bit) {
		assert(bit == 0 or bit == 1);
		assert(pos <= this->size);

		if (root == nullptr) {
			root = new Node(bit, 1, true);
		} else {
			insert(this->root, nullptr, bit, pos, this->size);
		}
		this->size++;
		this->num_one += (bit == 1);
	}


	void push_back(uint64_t bit) {
		assert(bit == 0 or bit == 1);

		this->insert(this->size, bit);
	}


	void erase(uint64_t pos) {
		assert(pos < this->size);

		uint64_t bit = this->remove(this->root, nullptr, pos, this->size, 0, true).first;
		this->size--;
		this->num_one -= (bit == 1);
	}


	void update(uint64_t pos, uint64_t bit) {
		assert(bit == 0 or bit == 1);
		assert(pos < this->size);

		if (bit == 1) {
			this->bitset(pos);
		}
		else {
			this->bitclear(pos);
		}
	}


	void bitset(uint64_t pos) {
		assert(pos < this->size);

		bool flip = bitset(this->root, pos);
		this->num_one += flip;
	}


	void bitclear(uint64_t pos) {
		assert(pos < this->size);

		bool flip = bitclear(this->root, pos);
		this->num_one -= flip;
	}


	void graphviz(const string &file_path) {


	}



	bool is_valid_tree(bool verbose) {
		if (this->root == nullptr) {
			if (this->size == 0 and this->num_one == 0) {
				return true;
			}
			cerr << "root is nullptr but size is " << this->size << " and num_one is " << this->num_one << endl;
			return false;
		}
		map<uint64_t, uint64_t> height;
		get_height(this->root, height);

		queue<Node*> que;
		que.emplace(this->root);

		while (not que.empty()) {
			Node *node = que.front(); que.pop();

			if (not node->is_valid_node()) {
				if (verbose) {
					cerr << "node " << node->no << " is invalid node" << endl;
					cerr << node->info() << endl;
				}
				return false;
			}

			if (not node->is_leaf) {
				auto left_height = height[node->left->no];
				auto right_height = height[node->right->no];

				if (node->balance != right_height - left_height) {
					if (verbose) {
						cerr << "node" << node->no << "'s balance is " << node->balance << "(left height:" << left_height << ", right height:" << right_height << ")" << endl;
					}
					return false;
				}


				if (node->balance < -1 or 1 < node->balance) {
					if (verbose) {
						cerr << "node" << node->no << "is not balanced." << "(balance:" << node->balance << ", left height:" << left_height << ", right height:" << right_height << ")" << endl;
					}
					return false;
				}

				que.emplace(node->left);
				que.emplace(node->right);
			}
			else {

				if (node->balance != 0) {
					if (verbose) {
						cerr << "node " << node->no << "'s balance is not 0" << endl;
					}
					return false;
				}
			}
		}
		return true;
	}

private:
	uint64_t access(const Node *node, uint64_t pos) {
		if (node->is_leaf) {
			assert(pos <= 2 * this->bits_size_limit);
			return (node->bits >> pos) & (uint64_t)1;
		}

		if (pos < node->num) {
			return this->access(node->left, pos);
		} else {
			return this->access(node->right, pos - node->num);
		}
	}

	uint64_t rank1(const Node *node, uint64_t pos, uint64_t ones) {
		if (node->is_leaf) {
			assert(node->bits_size >= pos);
			const uint64_t mask = ((uint64_t)1 << pos) - 1;
			return ones + popCount(node->bits & mask);
		}

		if (pos < node->num) {
			return this->rank1(node->left, pos, ones);
		} else {
			return this->rank1(node->right, pos - node->num, ones + node->ones);
		}
	}

	uint64_t select1(const Node *node, uint64_t pos, uint64_t rank) {
		if (node->is_leaf) {
			return pos + this->selectInBlock(node->bits, rank) + 1;
		}

		if (rank <= node->ones) {
			return this->select1(node->left, pos, rank);
		} else {
			return this->select1(node->right, pos + node->num, rank - node->ones);
		}
	}

	uint64_t select0(const Node *node, uint64_t pos, uint64_t rank) {
		if (node->is_leaf) {
			return pos + this->selectInBlock(~node->bits, rank) + 1;
		}

		if (rank <= (node->num - node->ones)) {
			return this->select0(node->left, pos, rank);
		} else {
			return this->select0(node->right, pos + node->num, rank - (node->num - node->ones));
		}
	}


	uint64_t selectInBlock(uint64_t bits, uint64_t rank) {
		const uint64_t x1 = bits - ((bits & 0xAAAAAAAAAAAAAAAALLU) >> (uint64_t)1);
		const uint64_t x2 = (x1 & 0x3333333333333333LLU) + ((x1 >> (uint64_t)2) & 0x3333333333333333LLU);
		const uint64_t x3 = (x2 + (x2 >> (uint64_t)4)) & 0x0F0F0F0F0F0F0F0FLLU;

		uint64_t pos = 0;
		for (;;  pos += 8) {
			const uint64_t rank_next = (x3 >> pos) & 0xFFLLU;
			if (rank <= rank_next) break;
			rank -= rank_next;
		}

		const uint64_t v2 = (x2 >> pos) & 0xFLLU;
		if (rank > v2) {
			rank -= v2;
			pos += 4;
		}

		const uint64_t v1 = (x1 >> pos) & 0x3LLU;
		if (rank > v1) {
			rank -= v1;
			pos += 2;
		}

		const uint64_t v0  = (bits >> pos) & 0x1LLU;
		if (v0 < rank) {
			pos += 1;
		}

		return pos;
	}



	int64_t insert(Node *node, Node *parent, uint64_t bit, uint64_t pos, uint64_t len) {
		assert(bit == 0 or bit == 1);
		if (node->is_leaf) {
			assert(pos <= 2 * this->bits_size_limit);


			const uint64_t up_mask = (((uint64_t)1 << (len - pos)) - 1) << pos;
			const uint64_t up = (node->bits & up_mask);


			const uint64_t down_mask = ((uint64_t)1 << pos) - 1;
			const uint64_t down = node->bits & down_mask;

			node->bits = (up << (uint64_t)1) | (bit << pos) | down;
			node->bits_size++;
			assert(node->bits_size == len + 1);


			if (len + 1 >= 2 * bits_size_limit) {
				this->splitNode(node, len + 1);
				return 1;
			}

			return 0;
		}

		if (pos < node->num) {
			const int64_t diff = this->insert(node->left, node, bit, pos, node->num);
			node->num += 1;
			node->ones += (bit == 1);
			return achieveBalance(parent, node, diff, 0);
		} else {
			const int64_t diff = this->insert(node->right, node, bit, pos - node->num, len - node->num);
			return achieveBalance(parent, node, 0, diff);
		}
	}



	pair<uint64_t, int64_t> remove(Node *node, Node *parent, uint64_t pos, uint64_t len, uint64_t ones, bool allow_under_flow) {
		if (node->is_leaf) {

			if (node != this->root and len <= bits_size_limit / 2 and not allow_under_flow) {
				return make_pair(NOTFOUND, 0);
			}

			assert(pos <= 2 * this->bits_size_limit);
			assert(pos < len);
			const uint64_t bit = (node->bits >> pos) & (uint64_t)1;


			const uint64_t up_mask = (((uint64_t)1 << (len - pos - 1)) - 1) << (pos + 1);
			const uint64_t up = (node->bits & up_mask);


			const uint64_t down_mask = ((uint64_t)1 << pos) - 1;
			const uint64_t down = node->bits & down_mask;

			node->bits = (up >> (uint64_t)1) | down;
			node->bits_size--;
			assert(node->bits_size == len - 1);

			return make_pair(bit, 0);
		}

		if (pos < node->num) {
			const auto bit_diff = this->remove(node->left, node, pos, node->num, node->ones, allow_under_flow);
			if (bit_diff.first == NOTFOUND) {
				return bit_diff;
			}

			node->ones -= (bit_diff.first == 1);

			if (node->num == bits_size_limit / 2) {
				const auto b_d = remove(node->right, node, 0, len - bits_size_limit / 2, 0, false);


				if (b_d.first == NOTFOUND) {
					assert(node->left->is_leaf);
					assert(node->left->bits_size == bits_size_limit / 2 - 1);

					mergeNodes(node->right, 0, len - bits_size_limit / 2, node->left->bits, bits_size_limit / 2 - 1, node->ones, true);
					this->replace(parent, node, node->right);
					return make_pair(bit_diff.first, -1);
				}


				assert(node->left->bits_size == bits_size_limit / 2 - 1);
				insert(node->left, node, b_d.first, bits_size_limit / 2 - 1, bits_size_limit / 2 - 1);
				node->ones += (b_d.first == 1);
			}
			else {
				node->num -= 1;
			}

			const int64_t diff = achieveBalance(parent, node, bit_diff.second, 0);
			return make_pair(bit_diff.first, diff);

		} else {
			const auto bit_diff = this->remove(node->right, node, pos - node->num, len - node->num, ones - node->ones, allow_under_flow);
			if (bit_diff.first == NOTFOUND) {
				return bit_diff;
			}

			ones -= (bit_diff.first == 1);

			if ((len - node->num) == bits_size_limit / 2) {
				const auto b_d = remove(node->left, node, node->num - 1, node->num, 0, false);


				if (b_d.first == NOTFOUND) {
					assert(node->right->is_leaf);
					assert(node->right->bits_size == bits_size_limit / 2 - 1);

					mergeNodes(node->left, node->num, node->num, node->right->bits, bits_size_limit / 2 - 1, ones - node->ones, false);
					this->replace(parent, node, node->left);
					return make_pair(bit_diff.first, -1);
				}


				insert(node->right, node, b_d.first, 0, bits_size_limit / 2 - 1);
				node->num -= 1;
				node->ones -= (b_d.first == 1);
			}

			const int64_t diff = achieveBalance(parent, node, 0, bit_diff.second);
			return make_pair(bit_diff.first, diff);
		}
	}


	bool bitset(Node *node, uint64_t pos) {
		if (node->is_leaf) {
			assert(pos <= 2 * this->bits_size_limit);
			const uint64_t bit = (node->bits >> pos) & 1;
			if (bit == 1) {
				return false;
			}

			node->bits |= ((uint64_t)1 << pos);
			return true;
		}

		if (pos < node->num) {
			bool flip = this->bitset(node->left, pos);
			node->ones += flip;
			return flip;
		} else {
			return this->bitset(node->right, pos - node->num);
		}
	}


	bool bitclear(Node *node, uint64_t pos) {
		if (node->is_leaf) {
			assert(pos <= 2 * this->bits_size_limit);

			const uint64_t bit = (node->bits >> pos) & 1;
			if (bit == 0) {
				return false;
			}
			node->bits &= ~((uint64_t)1 << pos);
			return true;
		}

		if (pos < node->num) {
			const bool flip = this->bitclear(node->left, pos);
			node->ones -= flip;
			return flip;
		} else {
			return this->bitclear(node->right, pos - node->num);
		}
	}


	void splitNode(Node *node, uint64_t len) {
		assert(node->is_leaf);
		assert(node->bits_size == len);


		const uint64_t left_size = len / 2;
		const uint64_t left_bits = node->bits & (((uint64_t)1 << left_size) - 1);
		node->left = new Node(left_bits, left_size, true);


		const uint64_t right_size = len - left_size;
		const uint64_t right_bits = node->bits >> left_size;
		node->right = new Node(right_bits, right_size, true);


		node->is_leaf = false;
		node->num = left_size;
		node->ones = this->popCount(left_bits);
		node->bits = 0;
		node->bits_size = 0;
	}


	void mergeNodes(Node *node, uint64_t pos, uint64_t len, uint64_t bits, uint64_t s, uint64_t ones, bool left) {
		if (node->is_leaf) {
			if (left) {
				node->bits = (node->bits << s) | bits;
			}
			else {
				assert(len == node->bits_size);
				node->bits = node->bits | (bits << len);
			}
			node->bits_size += s;
			return;
		}

		if (pos < node->num) {
			node->num += s;
			node->ones += ones;
			mergeNodes(node->left, pos, node->num, bits, s, ones, left);
		}
		else {
			mergeNodes(node->right, pos, len - node->num, bits, s, ones, left);
		}
	}



	int64_t achieveBalance(Node *parent, Node *node, int64_t leftHeightDiff, int64_t rightHeightDiff) {
		assert(-1 <= node->balance and node->balance <= 1);
		assert(-1 <= leftHeightDiff and leftHeightDiff <= 1);
		assert(-1 <= rightHeightDiff and rightHeightDiff <= 1);

		if (leftHeightDiff == 0 and rightHeightDiff == 0) {
			return 0;
		}

		int64_t heightDiff = 0;

		if ((node->balance <= 0 and leftHeightDiff > 0) or (node->balance >= 0 and rightHeightDiff > 0)) {
			++heightDiff;
		}

		if ((node->balance < 0 and leftHeightDiff < 0) or (node->balance > 0 and rightHeightDiff < 0)) {
			--heightDiff;
		}

		node->balance += -leftHeightDiff + rightHeightDiff;
		assert(-2 <= node->balance and node->balance <= 2);


		if (node->balance == -2) {
			assert(-1 <= node->left->balance and node->left->balance <= 1);
			if (node->left->balance != 0) {
				heightDiff--;
			}

			if (node->left->balance == 1) {
				replace(node, node->left, rotateLeft(node->left));
			}
			replace(parent, node, rotateRight(node));
		}

		else if (node->balance == 2) {
			assert(-1 <= node->right->balance and node->right->balance <= 1);
			if (node->right->balance != 0) {
				heightDiff--;
			}

			if (node->right->balance == -1) {
				replace(node, node->right, rotateRight(node->right));
			}
			replace(parent, node, rotateLeft(node));
		}

		return heightDiff;
	}


	Node *rotateLeft(Node *B) {
		Node *D = B->right;

		const int64_t heightC = 0;
		const int64_t heightE = heightC + D->balance;
		const int64_t heightA = max(heightC, heightE) + 1 - B->balance;

		B->right = D->left;
		D->left = B;

		B->balance = heightC - heightA;
		D->num += B->num;
		D->ones += B->ones;
		D->balance = heightE - (max(heightA, heightC) + 1);

		assert(-2 <= B->balance and B->balance <= 2);
		assert(-2 <= D->balance and D->balance <= 2);

		return D;
	}


	Node *rotateRight(Node *D) {
		Node *B = D->left;

		const int64_t heightC = 0;
		const int64_t heightA = heightC - B->balance;
		const int64_t heightE = max(heightA, heightC) + 1 + D->balance;

		D->left = B->right;
		B->right = D;

		D->num -= B->num;
		D->ones -= B->ones;
		D->balance = heightE - heightC;
		B->balance = max(heightC, heightE) + 1 - heightA;


		assert(-2 <= B->balance and B->balance <= 2);
		assert(-2 <= D->balance and D->balance <= 2);

		return B;
	}


	void replace(Node *parent, Node *oldNode, Node *newNode) {
		if (parent == nullptr) {
			this->root = newNode;
			return;
		}

		if (parent->left == oldNode) {
			parent->left = newNode;
		}
		else if (parent->right == oldNode) {
			parent->right = newNode;
		}
		else {
			throw "old node is not child";
		}
	}

	uint64_t popCount(uint64_t x) {
		x = (x & 0x5555555555555555ULL) + ((x >> (uint64_t)1) & 0x5555555555555555ULL);
		x = (x & 0x3333333333333333ULL) + ((x >> (uint64_t)2) & 0x3333333333333333ULL);
		x = (x + (x >> (uint64_t)4)) & 0x0f0f0f0f0f0f0f0fULL;
		x = x + (x >>  (uint64_t)8);
		x = x + (x >> (uint64_t)16);
		x = x + (x >> (uint64_t)32);
		return x & 0x7FLLU;
	}


	uint64_t get_height(Node *node, map<uint64_t, uint64_t> &height) {
		if (node->is_leaf) {
			return 0;
		}

		if (height.find(node->no) != height.end()) {
			return height[node->no];
		}

		auto left_height = get_height(node->left, height);
		auto right_height = get_height(node->right, height);
		return height[node->no] = max(left_height, right_height) + 1;
	}
};


class DynamicWaveletMatrix {
public:
	vector<DynamicBitVector> bit_arrays;
	vector<uint64_t> begin_one;

	uint64_t size;
	uint64_t maximum_element;
	uint64_t bit_size;

public:

	DynamicWaveletMatrix (uint64_t maximum_element) : size(0), maximum_element(maximum_element + 1) {
		this->bit_size = this->get_num_of_bit(maximum_element);
		if (bit_size == 0) {
			bit_size = 1;
		}
		this->begin_one.resize(bit_size);

		for (uint64_t i = 0; i < bit_size; ++i) {
			DynamicBitVector sv;
			bit_arrays.push_back(sv);
		}
	}

	DynamicWaveletMatrix (uint64_t num_of_alphabet, const vector<uint64_t> &array) : size(0), maximum_element(num_of_alphabet + 1) {
		this->bit_size = this->get_num_of_bit(num_of_alphabet);
		if (bit_size == 0) {
			bit_size = 1;
		}
		this->begin_one.resize(bit_size);

		if (array.size() == 0) {
			for (uint64_t i = 0; i < bit_size; ++i) {
				DynamicBitVector sv;
				bit_arrays.push_back(sv);
			}
			return;
		}

		size = array.size();

		vector<uint64_t> v(array), b(array.size(), 0);

		for (uint64_t i = 0; i < bit_size; ++i) {

			vector<uint64_t> temp;

			for (uint64_t j = 0; j < v.size(); ++j) {
				uint64_t c = v.at(j);
				uint64_t bit = (c >> (bit_size - i - 1)) & 1;
				if (bit == 0) {
					temp.push_back(c);
					b[j] = 0;
				}
			}

			this->begin_one.at(i) = temp.size();


			for (uint64_t j = 0; j < v.size(); ++j) {
				uint64_t c = v.at(j);
				uint64_t bit = (c >> (bit_size - i - 1)) & 1;
				if (bit == 1) {
					temp.push_back(c);
					b[j] = 1;
				}
			}

			DynamicBitVector dbv(b);
			bit_arrays.emplace_back(dbv);
			v = temp;
		}
	}


	uint64_t access(uint64_t pos) {
		if (pos >= this->size) { return NOTFOUND; }

		uint64_t c = 0;
		for (uint64_t i = 0; i < bit_arrays.size(); ++i) {
			uint64_t bit = bit_arrays.at(i).access(pos);
			c = (c <<= 1) | bit;
			pos = bit_arrays.at(i).rank(bit, pos);
			if (bit) {
				pos += this->begin_one.at(i);
			}
		}
		return c;
	}


	uint64_t rank(uint64_t c, uint64_t pos) {
		assert(pos <= size);
		if (c >= maximum_element) {
			return 0;
		}

		uint64_t left = 0, right = pos;
		for (uint64_t i = 0; i < bit_size; ++i) {
			const uint64_t bit = (c >> (bit_size - i - 1)) & 1;
			left = bit_arrays.at(i).rank(bit, left);
			right = bit_arrays.at(i).rank(bit, right);
			if (bit) {
				left += this->begin_one.at(i);
				right += this->begin_one.at(i);
			}
		}

		return right - left;
	}


	uint64_t select(uint64_t c, uint64_t rank) {
		assert(rank > 0);
		if (c >= maximum_element) {
			return NOTFOUND;
		}

		uint64_t left = 0;
		for (uint64_t i = 0; i < bit_size; ++i) {
			const uint64_t bit = (c >> (bit_size - i - 1)) & 1;
			left = bit_arrays.at(i).rank(bit, left);
			if (bit) {
				left += this->begin_one.at(i);
			}
		}

		uint64_t index = left + rank;
		for (uint64_t i = 0; i < bit_arrays.size(); ++i) {
			uint64_t bit = ((c >> i) & 1);
			if (bit == 1) {
				index -= this->begin_one.at(bit_size - i - 1);
			}
			index = this->bit_arrays.at(bit_size - i - 1).select(bit, index);
		}
		return index;
	}


	void insert(uint64_t pos, uint64_t c) {
		assert(pos <= this->size);

		for (uint64_t i = 0; i < bit_arrays.size(); ++i) {
			const uint64_t bit = (c >> (bit_size - i - 1)) & 1;
			bit_arrays.at(i).insert(pos, bit);
			pos = bit_arrays.at(i).rank(bit, pos);
			if (bit) {
				pos += this->begin_one.at(i);
			}
			else {
				this->begin_one.at(i)++;
			}
		}

		this->size++;
	}


	void push_back(uint64_t c) {
		this->insert(this->size, c);
	}


	void erase(uint64_t pos) {
		assert(pos < this->size);
		if (pos >= this->size) {
			throw "Segmentation fault";
		}

		for (uint64_t i = 0; i < bit_arrays.size(); ++i) {
			uint64_t bit = bit_arrays.at(i).access(pos);

			auto next_pos = bit_arrays.at(i).rank(bit, pos);
			bit_arrays.at(i).erase(pos);

			if (bit) {
				next_pos += this->begin_one.at(i);
			}
			else {
				this->begin_one.at(i)--;
			}
			pos = next_pos;
		}
		this->size--;
	}


	void update(uint64_t pos, uint64_t c) {
		assert(pos < this->size);
		this->erase(pos);
		this->insert(pos, c);
	}


	uint64_t maxRange(uint64_t begin_pos, uint64_t end_pos) {
		return quantileRange(begin_pos, end_pos, end_pos - begin_pos - 1);
	}


	uint64_t minRange(uint64_t begin_pos, uint64_t end_pos) {
		return quantileRange(begin_pos, end_pos, 0);
	}



	uint64_t quantileRange(uint64_t begin_pos, uint64_t end_pos, uint64_t k) {
		if ((end_pos > size || begin_pos >= end_pos) || (k >= end_pos - begin_pos)) {
			return NOTFOUND;
		}

		uint64_t val = 0;
		for (uint64_t i = 0; i < bit_size; ++i) {
			uint64_t num_of_zero_begin = bit_arrays.at(i).rank(0, begin_pos);
			uint64_t num_of_zero_end = bit_arrays.at(i).rank(0, end_pos);
			uint64_t num_of_zero = num_of_zero_end - num_of_zero_begin;
			uint64_t bit = (k < num_of_zero) ? 0 : 1;

			if (bit) {
				k -= num_of_zero;
				begin_pos = this->begin_one.at(i) + begin_pos - num_of_zero_begin;
				end_pos = this->begin_one.at(i) + end_pos - num_of_zero_end;
			}
			else {
				begin_pos = num_of_zero_begin;
				end_pos = num_of_zero_begin + num_of_zero;
			}

			val = ((val << 1) | bit);
		}

		uint64_t left = 0;
		for (uint64_t i = 0; i < bit_size; ++i) {
			const uint64_t bit = (val >> (bit_size - i - 1)) & 1;
			left = bit_arrays.at(i).rank(bit, left);
			if (bit) {
				left += this->begin_one.at(i);
			}
		}

		uint64_t rank = begin_pos + k - left + 1;
		return select(val, rank) - 1;
	}


	uint64_t rankLessThan(uint64_t c, uint64_t pos) {
		uint64_t rank_less_than = 0, rank_more_than = 0, rank = 0;
		rankAll(c, 0, pos, rank, rank_less_than, rank_more_than);
		return rank_less_than;
	}


	uint64_t rankMoreThan(uint64_t c, uint64_t pos) {
		uint64_t rank_less_than = 0, rank_more_than = 0, rank = 0;
		rankAll(c, 0, pos, rank, rank_less_than, rank_more_than);
		return rank_more_than;
	}


	void rankAll(uint64_t c, uint64_t begin_pos, uint64_t end_pos, uint64_t &rank, uint64_t &rank_less_than, uint64_t &rank_more_than) {
		if (c >= maximum_element || begin_pos >= size || end_pos > size) {
			rank_less_than = NOTFOUND;
			rank_more_than = NOTFOUND;
			rank           = NOTFOUND;
			return;
		}
		rank_less_than = 0;
		rank_more_than = 0;
		rank = 0;

		if (begin_pos >= end_pos) {
			return;
		}

		vector<uint64_t> more_and_less(2, 0);
		for (uint64_t i = 0; i < bit_size; ++i) {
			const uint64_t bit = (c >> (bit_size - i - 1)) & 1;

			const uint64_t range_bits = end_pos - begin_pos;
			const uint64_t begin_zero = bit_arrays.at(i).rank(0, begin_pos);
			const uint64_t end_zero = bit_arrays.at(i).rank(0, end_pos);

			if (bit) {
				begin_pos += this->begin_one.at(i) - begin_zero;
				end_pos += this->begin_one.at(i) - end_zero;
			} else {
				begin_pos = begin_zero;
				end_pos = end_zero;
			}
			more_and_less.at(bit) += range_bits - (end_pos - begin_pos);
		}

		rank_less_than = more_and_less.at(1);
		rank_more_than = more_and_less.at(0);
		rank = end_pos - begin_pos;
	}


	vector<pair<uint64_t, uint64_t>> topk(uint64_t s, uint64_t e, uint64_t k) {
		assert(s < e);
		vector<pair<uint64_t, uint64_t>> result;

		auto c = [](const tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t> &l, const tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t> &r) {

			if (get<0>(l) != get<0>(r)) {
				return get<0>(l) < get<0>(r);
			}

			if (get<3>(l) != get<3>(r)) {
				return get<3>(l) > get<3>(r);
			}

			if (get<4>(l) != get<4>(r)) {
				return get<4>(l) > get<4>(r);
			}
			return true;
		};

		priority_queue<tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t>, vector<tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t>>, decltype(c)> que(c);
		que.push(make_tuple(e - s, s, e, 0, 0));

		while (not que.empty()) {
			auto element = que.top(); que.pop();
			uint64_t width, left, right, depth, value;
			tie(width, left, right, depth, value) = element;

			if (depth >= this->bit_size) {
				result.emplace_back(make_pair(value, right - left));
				if (result.size() >= k) {
					break;
				}
				continue;
			}


			const uint64_t left0 = this->bit_arrays.at(depth).rank(0, left);
			const uint64_t right0 = this->bit_arrays.at(depth).rank(0, right);
			if (left0 < right0) {
				que.push(make_tuple(right0 - left0, left0, right0, depth + 1, value));
			}


			const uint64_t left1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, left);
			const uint64_t right1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, right);
			if (left1 < right1) {
				que.push(make_tuple(right1 - left1, left1, right1, depth + 1, value | (1 << bit_size - depth - 1)));
			}
		}

		return result;

	};


	vector<tuple<uint64_t, uint64_t, uint64_t>> intersect(uint64_t _s1, uint64_t _e1, uint64_t _s2, uint64_t _e2) {
		assert(_s1 < _e1);
		assert(_s2 < _e2);

		vector<tuple<uint64_t, uint64_t, uint64_t>> intersection;

		queue<tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t>> que;
		que.push(make_tuple(_s1, _e1, _s2, _e2, 0, 0));
		while (not que.empty()) {
			auto e = que.front(); que.pop();
			uint64_t s1, e1, s2, e2, depth, value;
			tie(s1, e1, s2, e2, depth, value) = e;

			if (depth >= this->bit_size) {
				intersection.emplace_back(make_tuple(value, e1 - s1, e2 - s2));
				continue;
			}


			uint64_t s1_0 = this->bit_arrays.at(depth).rank(0, s1);
			uint64_t e1_0 = this->bit_arrays.at(depth).rank(0, e1);
			uint64_t s2_0 = this->bit_arrays.at(depth).rank(0, s2);
			uint64_t e2_0 = this->bit_arrays.at(depth).rank(0, e2);

			if (s1_0 != e1_0 and s2_0 != e2_0) {
				que.push(make_tuple(s1_0, e1_0, s2_0, e2_0, depth + 1, value));
			}


			uint64_t s1_1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, s1);
			uint64_t e1_1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, e1);
			uint64_t s2_1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, s2);
			uint64_t e2_1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, e2);

			if (s1_1 != e1_1 and s2_1 != e2_1) {
				que.push(make_tuple(s1_1, e1_1, s2_1, e2_1, depth + 1, value | (1 << bit_size - depth - 1)));
			}
		}

		return intersection;
	};

private:
	uint64_t get_num_of_bit(uint64_t x) {
		if (x == 0) return 0;
		x--;
		uint64_t bit_num = 0;
		while (x >> bit_num) {
			++bit_num;
		}
		return bit_num;
	}
};

int main() {
	fast;
	int n, q; cin >> n >> q;
	vector<uint64_t> v(n);
	for (auto &x : v)cin >> x;
	DynamicWaveletMatrix dwm(10000000, v);
	while (q--) {
		int ty, l, r;
		cin >> ty >> l >> r;
		if (ty == 0){
			dwm.insert(l, dwm.access(r));
			dwm.erase(r + 1);
		} else if (ty == 1) {
			cout<<dwm.access(dwm.minRange(l,r+1))<<endl;
		} else {
			dwm.update(l,r);
		}
	}
}
accuracy: 1
time_ms: 3300
memory_kb: 39020
final_rank: 19

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define fast ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define endl '\n'
#define ll long long

enum {
	NOTFOUND = 0xFFFFFFFFFFFFFFFFLLU
};

uint64_t NODE_NO = 0;

class Node {
public:
	uint64_t no;
	uint64_t num;
	uint64_t ones;
	Node *left;
	Node *right;
	int64_t balance;
	uint64_t bits;
	uint64_t bits_size;

	bool is_leaf;

	Node(uint64_t bits, uint64_t bits_size, bool is_leaf) : no(NODE_NO++), num(0), ones(0), bits(bits), bits_size(bits_size), is_leaf(is_leaf), left(nullptr), right(nullptr), balance(0) {}

	bool is_valid_node() {
		if (is_leaf) {
			if (num != 0) { return false; }
			if (ones != 0) { return false; }
			if (left != nullptr) { return false; }
			if (right != nullptr) { return false; }
		}
		else {
			if (num == 0) { return false; }
			if (left == nullptr) { return false; }
			if (right == nullptr) { return false; }
			if (bits != 0) { return false; }
			if (bits_size != 0) { return false; }
			if (ones > num) {return false; }
		}
		return true;
	}

	string info() {
		string str = "No:" + to_string(this->no) + "\n";
		if (is_leaf) {
			str += "size:" + to_string(this->bits_size) + "\n";
			for (int i = 0; i < bits_size; ++i) {
				str += to_string((bits >> (uint64_t)i) & (uint64_t)1);
			}
		}
		else {
			str += "num:" + to_string(this->num) + " ones:" + to_string(this->ones) + "\n";
		}

		return str;
	}
};

class DynamicBitVector {
public:
	Node *root;
	uint64_t size;
	uint64_t num_one;
	const uint64_t bits_size_limit = 32;

	DynamicBitVector(): root(nullptr), size(0), num_one(0) {}

	DynamicBitVector(vector<uint64_t> &v): root(nullptr), size(0), num_one(0) {
		if (v.size() == 0) {
			return;
		}

		deque<pair<Node*, uint64_t>> leaves;
		for (int i = 0; i < v.size(); i += this->bits_size_limit) {
			uint64_t bits = 0;
			const uint64_t bits_size = min(this->bits_size_limit, (uint64_t)v.size() - i);
			for (int j = 0; j < bits_size; ++j) {
				assert(v[i + j] == 0 or v[i + j] == 1);
				if (v[i + j] == 1) {
					bits |= (uint64_t)1 << j;
				}
			}

			leaves.emplace_back(make_pair(new Node(bits, bits_size, true), bits_size));
		}


		deque<tuple<Node*, uint64_t, uint64_t, uint64_t>> nodes;
		while (not leaves.empty()) {
			const auto node = leaves.front().first;
			const auto bits_size = leaves.front().second;
			leaves.pop_front();
			nodes.emplace_back(make_tuple(node, bits_size, popCount(node->bits), 0));
		}

		while (nodes.size() > 1) {

			deque<tuple<Node*, uint64_t, uint64_t, uint64_t>> next_nodes;
			while (not nodes.empty()) {

				if (nodes.size() == 1) {
					nodes.push_front(next_nodes.back());
					next_nodes.pop_back();
				}

				Node *left_node;
				uint64_t left_num, left_ones, left_height;
				tie(left_node, left_num, left_ones, left_height) = nodes.front(); nodes.pop_front();

				Node *right_node;
				uint64_t right_num, right_ones, right_height;
				tie(right_node, right_num, right_ones, right_height) = nodes.front(); nodes.pop_front();

				const auto internal_node = new Node(0, 0, false);
				internal_node->num = left_num;
				internal_node->ones = left_ones;
				internal_node->left = left_node;
				internal_node->right = right_node;
				internal_node->balance = right_height - left_height;

				next_nodes.emplace_back(make_tuple(internal_node, left_num + right_num, left_ones + right_ones, max(left_height, right_height) + 1));
			}

			nodes = next_nodes;
		}

		uint64_t height;
		tie(this->root, this->size, this->num_one, height) = nodes.front(); nodes.pop_front();
		assert(this->size == v.size());
	}


	uint64_t access(uint64_t pos) {
		assert(pos < this->size);

		return access(this->root, pos);
	}


	uint64_t rank(uint64_t bit, uint64_t pos) {
		assert(bit == 0 or bit == 1);
		assert(pos <= this->size);

		if (bit) {
			return rank1(this->root, pos, 0);
		}
		else {
			return pos - rank1(this->root, pos, 0);
		}
	}


	uint64_t select(uint64_t bit, uint64_t rank) {
		assert(bit == 0 or bit == 1);
		assert(rank > 0);

		if (bit == 0 and rank > this->size - this-> num_one) { return NOTFOUND; }
		if (bit == 1 and rank > this-> num_one)              { return NOTFOUND; }

		if (bit) {
			return select1(this->root, 0, rank);
		}
		else {
			return select0(this->root, 0, rank);
		}
	}


	void insert(uint64_t pos, uint64_t bit) {
		assert(bit == 0 or bit == 1);
		assert(pos <= this->size);

		if (root == nullptr) {
			root = new Node(bit, 1, true);
		} else {
			insert(this->root, nullptr, bit, pos, this->size);
		}
		this->size++;
		this->num_one += (bit == 1);
	}


	void push_back(uint64_t bit) {
		assert(bit == 0 or bit == 1);

		this->insert(this->size, bit);
	}


	void erase(uint64_t pos) {
		assert(pos < this->size);

		uint64_t bit = this->remove(this->root, nullptr, pos, this->size, 0, true).first;
		this->size--;
		this->num_one -= (bit == 1);
	}


	void update(uint64_t pos, uint64_t bit) {
		assert(bit == 0 or bit == 1);
		assert(pos < this->size);

		if (bit == 1) {
			this->bitset(pos);
		}
		else {
			this->bitclear(pos);
		}
	}


	void bitset(uint64_t pos) {
		assert(pos < this->size);

		bool flip = bitset(this->root, pos);
		this->num_one += flip;
	}


	void bitclear(uint64_t pos) {
		assert(pos < this->size);

		bool flip = bitclear(this->root, pos);
		this->num_one -= flip;
	}


	void graphviz(const string &file_path) {


	}



	bool is_valid_tree(bool verbose) {
		if (this->root == nullptr) {
			if (this->size == 0 and this->num_one == 0) {
				return true;
			}
			cerr << "root is nullptr but size is " << this->size << " and num_one is " << this->num_one << endl;
			return false;
		}
		map<uint64_t, uint64_t> height;
		get_height(this->root, height);

		queue<Node*> que;
		que.emplace(this->root);

		while (not que.empty()) {
			Node *node = que.front(); que.pop();

			if (not node->is_valid_node()) {
				if (verbose) {
					cerr << "node " << node->no << " is invalid node" << endl;
					cerr << node->info() << endl;
				}
				return false;
			}

			if (not node->is_leaf) {
				auto left_height = height[node->left->no];
				auto right_height = height[node->right->no];

				if (node->balance != right_height - left_height) {
					if (verbose) {
						cerr << "node" << node->no << "'s balance is " << node->balance << "(left height:" << left_height << ", right height:" << right_height << ")" << endl;
					}
					return false;
				}


				if (node->balance < -1 or 1 < node->balance) {
					if (verbose) {
						cerr << "node" << node->no << "is not balanced." << "(balance:" << node->balance << ", left height:" << left_height << ", right height:" << right_height << ")" << endl;
					}
					return false;
				}

				que.emplace(node->left);
				que.emplace(node->right);
			}
			else {

				if (node->balance != 0) {
					if (verbose) {
						cerr << "node " << node->no << "'s balance is not 0" << endl;
					}
					return false;
				}
			}
		}
		return true;
	}

private:
	uint64_t access(const Node *node, uint64_t pos) {
		if (node->is_leaf) {
			assert(pos <= 2 * this->bits_size_limit);
			return (node->bits >> pos) & (uint64_t)1;
		}

		if (pos < node->num) {
			return this->access(node->left, pos);
		} else {
			return this->access(node->right, pos - node->num);
		}
	}

	uint64_t rank1(const Node *node, uint64_t pos, uint64_t ones) {
		if (node->is_leaf) {
			assert(node->bits_size >= pos);
			const uint64_t mask = ((uint64_t)1 << pos) - 1;
			return ones + popCount(node->bits & mask);
		}

		if (pos < node->num) {
			return this->rank1(node->left, pos, ones);
		} else {
			return this->rank1(node->right, pos - node->num, ones + node->ones);
		}
	}

	uint64_t select1(const Node *node, uint64_t pos, uint64_t rank) {
		if (node->is_leaf) {
			return pos + this->selectInBlock(node->bits, rank) + 1;
		}

		if (rank <= node->ones) {
			return this->select1(node->left, pos, rank);
		} else {
			return this->select1(node->right, pos + node->num, rank - node->ones);
		}
	}

	uint64_t select0(const Node *node, uint64_t pos, uint64_t rank) {
		if (node->is_leaf) {
			return pos + this->selectInBlock(~node->bits, rank) + 1;
		}

		if (rank <= (node->num - node->ones)) {
			return this->select0(node->left, pos, rank);
		} else {
			return this->select0(node->right, pos + node->num, rank - (node->num - node->ones));
		}
	}


	uint64_t selectInBlock(uint64_t bits, uint64_t rank) {
		const uint64_t x1 = bits - ((bits & 0xAAAAAAAAAAAAAAAALLU) >> (uint64_t)1);
		const uint64_t x2 = (x1 & 0x3333333333333333LLU) + ((x1 >> (uint64_t)2) & 0x3333333333333333LLU);
		const uint64_t x3 = (x2 + (x2 >> (uint64_t)4)) & 0x0F0F0F0F0F0F0F0FLLU;

		uint64_t pos = 0;
		for (;;  pos += 8) {
			const uint64_t rank_next = (x3 >> pos) & 0xFFLLU;
			if (rank <= rank_next) break;
			rank -= rank_next;
		}

		const uint64_t v2 = (x2 >> pos) & 0xFLLU;
		if (rank > v2) {
			rank -= v2;
			pos += 4;
		}

		const uint64_t v1 = (x1 >> pos) & 0x3LLU;
		if (rank > v1) {
			rank -= v1;
			pos += 2;
		}

		const uint64_t v0  = (bits >> pos) & 0x1LLU;
		if (v0 < rank) {
			pos += 1;
		}

		return pos;
	}



	int64_t insert(Node *node, Node *parent, uint64_t bit, uint64_t pos, uint64_t len) {
		assert(bit == 0 or bit == 1);
		if (node->is_leaf) {
			assert(pos <= 2 * this->bits_size_limit);


			const uint64_t up_mask = (((uint64_t)1 << (len - pos)) - 1) << pos;
			const uint64_t up = (node->bits & up_mask);


			const uint64_t down_mask = ((uint64_t)1 << pos) - 1;
			const uint64_t down = node->bits & down_mask;

			node->bits = (up << (uint64_t)1) | (bit << pos) | down;
			node->bits_size++;
			assert(node->bits_size == len + 1);


			if (len + 1 >= 2 * bits_size_limit) {
				this->splitNode(node, len + 1);
				return 1;
			}

			return 0;
		}

		if (pos < node->num) {
			const int64_t diff = this->insert(node->left, node, bit, pos, node->num);
			node->num += 1;
			node->ones += (bit == 1);
			return achieveBalance(parent, node, diff, 0);
		} else {
			const int64_t diff = this->insert(node->right, node, bit, pos - node->num, len - node->num);
			return achieveBalance(parent, node, 0, diff);
		}
	}



	pair<uint64_t, int64_t> remove(Node *node, Node *parent, uint64_t pos, uint64_t len, uint64_t ones, bool allow_under_flow) {
		if (node->is_leaf) {

			if (node != this->root and len <= bits_size_limit / 2 and not allow_under_flow) {
				return make_pair(NOTFOUND, 0);
			}

			assert(pos <= 2 * this->bits_size_limit);
			assert(pos < len);
			const uint64_t bit = (node->bits >> pos) & (uint64_t)1;


			const uint64_t up_mask = (((uint64_t)1 << (len - pos - 1)) - 1) << (pos + 1);
			const uint64_t up = (node->bits & up_mask);


			const uint64_t down_mask = ((uint64_t)1 << pos) - 1;
			const uint64_t down = node->bits & down_mask;

			node->bits = (up >> (uint64_t)1) | down;
			node->bits_size--;
			assert(node->bits_size == len - 1);

			return make_pair(bit, 0);
		}

		if (pos < node->num) {
			const auto bit_diff = this->remove(node->left, node, pos, node->num, node->ones, allow_under_flow);
			if (bit_diff.first == NOTFOUND) {
				return bit_diff;
			}

			node->ones -= (bit_diff.first == 1);

			if (node->num == bits_size_limit / 2) {
				const auto b_d = remove(node->right, node, 0, len - bits_size_limit / 2, 0, false);


				if (b_d.first == NOTFOUND) {
					assert(node->left->is_leaf);
					assert(node->left->bits_size == bits_size_limit / 2 - 1);

					mergeNodes(node->right, 0, len - bits_size_limit / 2, node->left->bits, bits_size_limit / 2 - 1, node->ones, true);
					this->replace(parent, node, node->right);
					return make_pair(bit_diff.first, -1);
				}


				assert(node->left->bits_size == bits_size_limit / 2 - 1);
				insert(node->left, node, b_d.first, bits_size_limit / 2 - 1, bits_size_limit / 2 - 1);
				node->ones += (b_d.first == 1);
			}
			else {
				node->num -= 1;
			}

			const int64_t diff = achieveBalance(parent, node, bit_diff.second, 0);
			return make_pair(bit_diff.first, diff);

		} else {
			const auto bit_diff = this->remove(node->right, node, pos - node->num, len - node->num, ones - node->ones, allow_under_flow);
			if (bit_diff.first == NOTFOUND) {
				return bit_diff;
			}

			ones -= (bit_diff.first == 1);

			if ((len - node->num) == bits_size_limit / 2) {
				const auto b_d = remove(node->left, node, node->num - 1, node->num, 0, false);


				if (b_d.first == NOTFOUND) {
					assert(node->right->is_leaf);
					assert(node->right->bits_size == bits_size_limit / 2 - 1);

					mergeNodes(node->left, node->num, node->num, node->right->bits, bits_size_limit / 2 - 1, ones - node->ones, false);
					this->replace(parent, node, node->left);
					return make_pair(bit_diff.first, -1);
				}


				insert(node->right, node, b_d.first, 0, bits_size_limit / 2 - 1);
				node->num -= 1;
				node->ones -= (b_d.first == 1);
			}

			const int64_t diff = achieveBalance(parent, node, 0, bit_diff.second);
			return make_pair(bit_diff.first, diff);
		}
	}


	bool bitset(Node *node, uint64_t pos) {
		if (node->is_leaf) {
			assert(pos <= 2 * this->bits_size_limit);
			const uint64_t bit = (node->bits >> pos) & 1;
			if (bit == 1) {
				return false;
			}

			node->bits |= ((uint64_t)1 << pos);
			return true;
		}

		if (pos < node->num) {
			bool flip = this->bitset(node->left, pos);
			node->ones += flip;
			return flip;
		} else {
			return this->bitset(node->right, pos - node->num);
		}
	}


	bool bitclear(Node *node, uint64_t pos) {
		if (node->is_leaf) {
			assert(pos <= 2 * this->bits_size_limit);

			const uint64_t bit = (node->bits >> pos) & 1;
			if (bit == 0) {
				return false;
			}
			node->bits &= ~((uint64_t)1 << pos);
			return true;
		}

		if (pos < node->num) {
			const bool flip = this->bitclear(node->left, pos);
			node->ones -= flip;
			return flip;
		} else {
			return this->bitclear(node->right, pos - node->num);
		}
	}


	void splitNode(Node *node, uint64_t len) {
		assert(node->is_leaf);
		assert(node->bits_size == len);


		const uint64_t left_size = len / 2;
		const uint64_t left_bits = node->bits & (((uint64_t)1 << left_size) - 1);
		node->left = new Node(left_bits, left_size, true);


		const uint64_t right_size = len - left_size;
		const uint64_t right_bits = node->bits >> left_size;
		node->right = new Node(right_bits, right_size, true);


		node->is_leaf = false;
		node->num = left_size;
		node->ones = this->popCount(left_bits);
		node->bits = 0;
		node->bits_size = 0;
	}


	void mergeNodes(Node *node, uint64_t pos, uint64_t len, uint64_t bits, uint64_t s, uint64_t ones, bool left) {
		if (node->is_leaf) {
			if (left) {
				node->bits = (node->bits << s) | bits;
			}
			else {
				assert(len == node->bits_size);
				node->bits = node->bits | (bits << len);
			}
			node->bits_size += s;
			return;
		}

		if (pos < node->num) {
			node->num += s;
			node->ones += ones;
			mergeNodes(node->left, pos, node->num, bits, s, ones, left);
		}
		else {
			mergeNodes(node->right, pos, len - node->num, bits, s, ones, left);
		}
	}



	int64_t achieveBalance(Node *parent, Node *node, int64_t leftHeightDiff, int64_t rightHeightDiff) {
		assert(-1 <= node->balance and node->balance <= 1);
		assert(-1 <= leftHeightDiff and leftHeightDiff <= 1);
		assert(-1 <= rightHeightDiff and rightHeightDiff <= 1);

		if (leftHeightDiff == 0 and rightHeightDiff == 0) {
			return 0;
		}

		int64_t heightDiff = 0;

		if ((node->balance <= 0 and leftHeightDiff > 0) or (node->balance >= 0 and rightHeightDiff > 0)) {
			++heightDiff;
		}

		if ((node->balance < 0 and leftHeightDiff < 0) or (node->balance > 0 and rightHeightDiff < 0)) {
			--heightDiff;
		}

		node->balance += -leftHeightDiff + rightHeightDiff;
		assert(-2 <= node->balance and node->balance <= 2);


		if (node->balance == -2) {
			assert(-1 <= node->left->balance and node->left->balance <= 1);
			if (node->left->balance != 0) {
				heightDiff--;
			}

			if (node->left->balance == 1) {
				replace(node, node->left, rotateLeft(node->left));
			}
			replace(parent, node, rotateRight(node));
		}

		else if (node->balance == 2) {
			assert(-1 <= node->right->balance and node->right->balance <= 1);
			if (node->right->balance != 0) {
				heightDiff--;
			}

			if (node->right->balance == -1) {
				replace(node, node->right, rotateRight(node->right));
			}
			replace(parent, node, rotateLeft(node));
		}

		return heightDiff;
	}


	Node *rotateLeft(Node *B) {
		Node *D = B->right;

		const int64_t heightC = 0;
		const int64_t heightE = heightC + D->balance;
		const int64_t heightA = max(heightC, heightE) + 1 - B->balance;

		B->right = D->left;
		D->left = B;

		B->balance = heightC - heightA;
		D->num += B->num;
		D->ones += B->ones;
		D->balance = heightE - (max(heightA, heightC) + 1);

		assert(-2 <= B->balance and B->balance <= 2);
		assert(-2 <= D->balance and D->balance <= 2);

		return D;
	}


	Node *rotateRight(Node *D) {
		Node *B = D->left;

		const int64_t heightC = 0;
		const int64_t heightA = heightC - B->balance;
		const int64_t heightE = max(heightA, heightC) + 1 + D->balance;

		D->left = B->right;
		B->right = D;

		D->num -= B->num;
		D->ones -= B->ones;
		D->balance = heightE - heightC;
		B->balance = max(heightC, heightE) + 1 - heightA;


		assert(-2 <= B->balance and B->balance <= 2);
		assert(-2 <= D->balance and D->balance <= 2);

		return B;
	}


	void replace(Node *parent, Node *oldNode, Node *newNode) {
		if (parent == nullptr) {
			this->root = newNode;
			return;
		}

		if (parent->left == oldNode) {
			parent->left = newNode;
		}
		else if (parent->right == oldNode) {
			parent->right = newNode;
		}
		else {
			throw "old node is not child";
		}
	}

	uint64_t popCount(uint64_t x) {
		x = (x & 0x5555555555555555ULL) + ((x >> (uint64_t)1) & 0x5555555555555555ULL);
		x = (x & 0x3333333333333333ULL) + ((x >> (uint64_t)2) & 0x3333333333333333ULL);
		x = (x + (x >> (uint64_t)4)) & 0x0f0f0f0f0f0f0f0fULL;
		x = x + (x >>  (uint64_t)8);
		x = x + (x >> (uint64_t)16);
		x = x + (x >> (uint64_t)32);
		return x & 0x7FLLU;
	}


	uint64_t get_height(Node *node, map<uint64_t, uint64_t> &height) {
		if (node->is_leaf) {
			return 0;
		}

		if (height.find(node->no) != height.end()) {
			return height[node->no];
		}

		auto left_height = get_height(node->left, height);
		auto right_height = get_height(node->right, height);
		return height[node->no] = max(left_height, right_height) + 1;
	}
};


class DynamicWaveletMatrix {
public:
	vector<DynamicBitVector> bit_arrays;
	vector<uint64_t> begin_one;

	uint64_t size;
	uint64_t maximum_element;
	uint64_t bit_size;

public:

	DynamicWaveletMatrix (uint64_t maximum_element) : size(0), maximum_element(maximum_element + 1) {
		this->bit_size = this->get_num_of_bit(maximum_element);
		if (bit_size == 0) {
			bit_size = 1;
		}
		this->begin_one.resize(bit_size);

		for (uint64_t i = 0; i < bit_size; ++i) {
			DynamicBitVector sv;
			bit_arrays.push_back(sv);
		}
	}

	DynamicWaveletMatrix (uint64_t num_of_alphabet, const vector<uint64_t> &array) : size(0), maximum_element(num_of_alphabet + 1) {
		this->bit_size = this->get_num_of_bit(num_of_alphabet);
		if (bit_size == 0) {
			bit_size = 1;
		}
		this->begin_one.resize(bit_size);

		if (array.size() == 0) {
			for (uint64_t i = 0; i < bit_size; ++i) {
				DynamicBitVector sv;
				bit_arrays.push_back(sv);
			}
			return;
		}

		size = array.size();

		vector<uint64_t> v(array), b(array.size(), 0);

		for (uint64_t i = 0; i < bit_size; ++i) {

			vector<uint64_t> temp;

			for (uint64_t j = 0; j < v.size(); ++j) {
				uint64_t c = v.at(j);
				uint64_t bit = (c >> (bit_size - i - 1)) & 1;
				if (bit == 0) {
					temp.push_back(c);
					b[j] = 0;
				}
			}

			this->begin_one.at(i) = temp.size();


			for (uint64_t j = 0; j < v.size(); ++j) {
				uint64_t c = v.at(j);
				uint64_t bit = (c >> (bit_size - i - 1)) & 1;
				if (bit == 1) {
					temp.push_back(c);
					b[j] = 1;
				}
			}

			DynamicBitVector dbv(b);
			bit_arrays.emplace_back(dbv);
			v = temp;
		}
	}


	uint64_t access(uint64_t pos) {
		if (pos >= this->size) { return NOTFOUND; }

		uint64_t c = 0;
		for (uint64_t i = 0; i < bit_arrays.size(); ++i) {
			uint64_t bit = bit_arrays.at(i).access(pos);
			c = (c <<= 1) | bit;
			pos = bit_arrays.at(i).rank(bit, pos);
			if (bit) {
				pos += this->begin_one.at(i);
			}
		}
		return c;
	}


	uint64_t rank(uint64_t c, uint64_t pos) {
		assert(pos <= size);
		if (c >= maximum_element) {
			return 0;
		}

		uint64_t left = 0, right = pos;
		for (uint64_t i = 0; i < bit_size; ++i) {
			const uint64_t bit = (c >> (bit_size - i - 1)) & 1;
			left = bit_arrays.at(i).rank(bit, left);
			right = bit_arrays.at(i).rank(bit, right);
			if (bit) {
				left += this->begin_one.at(i);
				right += this->begin_one.at(i);
			}
		}

		return right - left;
	}


	uint64_t select(uint64_t c, uint64_t rank) {
		assert(rank > 0);
		if (c >= maximum_element) {
			return NOTFOUND;
		}

		uint64_t left = 0;
		for (uint64_t i = 0; i < bit_size; ++i) {
			const uint64_t bit = (c >> (bit_size - i - 1)) & 1;
			left = bit_arrays.at(i).rank(bit, left);
			if (bit) {
				left += this->begin_one.at(i);
			}
		}

		uint64_t index = left + rank;
		for (uint64_t i = 0; i < bit_arrays.size(); ++i) {
			uint64_t bit = ((c >> i) & 1);
			if (bit == 1) {
				index -= this->begin_one.at(bit_size - i - 1);
			}
			index = this->bit_arrays.at(bit_size - i - 1).select(bit, index);
		}
		return index;
	}


	void insert(uint64_t pos, uint64_t c) {
		assert(pos <= this->size);

		for (uint64_t i = 0; i < bit_arrays.size(); ++i) {
			const uint64_t bit = (c >> (bit_size - i - 1)) & 1;
			bit_arrays.at(i).insert(pos, bit);
			pos = bit_arrays.at(i).rank(bit, pos);
			if (bit) {
				pos += this->begin_one.at(i);
			}
			else {
				this->begin_one.at(i)++;
			}
		}

		this->size++;
	}


	void push_back(uint64_t c) {
		this->insert(this->size, c);
	}


	void erase(uint64_t pos) {
		assert(pos < this->size);
		if (pos >= this->size) {
			throw "Segmentation fault";
		}

		for (uint64_t i = 0; i < bit_arrays.size(); ++i) {
			uint64_t bit = bit_arrays.at(i).access(pos);

			auto next_pos = bit_arrays.at(i).rank(bit, pos);
			bit_arrays.at(i).erase(pos);

			if (bit) {
				next_pos += this->begin_one.at(i);
			}
			else {
				this->begin_one.at(i)--;
			}
			pos = next_pos;
		}
		this->size--;
	}


	void update(uint64_t pos, uint64_t c) {
		assert(pos < this->size);
		this->erase(pos);
		this->insert(pos, c);
	}


	uint64_t maxRange(uint64_t begin_pos, uint64_t end_pos) {
		return quantileRange(begin_pos, end_pos, end_pos - begin_pos - 1);
	}


	uint64_t minRange(uint64_t begin_pos, uint64_t end_pos) {
		return quantileRange(begin_pos, end_pos, 0);
	}



	uint64_t quantileRange(uint64_t begin_pos, uint64_t end_pos, uint64_t k) {
		if ((end_pos > size || begin_pos >= end_pos) || (k >= end_pos - begin_pos)) {
			return NOTFOUND;
		}

		uint64_t val = 0;
		for (uint64_t i = 0; i < bit_size; ++i) {
			uint64_t num_of_zero_begin = bit_arrays.at(i).rank(0, begin_pos);
			uint64_t num_of_zero_end = bit_arrays.at(i).rank(0, end_pos);
			uint64_t num_of_zero = num_of_zero_end - num_of_zero_begin;
			uint64_t bit = (k < num_of_zero) ? 0 : 1;

			if (bit) {
				k -= num_of_zero;
				begin_pos = this->begin_one.at(i) + begin_pos - num_of_zero_begin;
				end_pos = this->begin_one.at(i) + end_pos - num_of_zero_end;
			}
			else {
				begin_pos = num_of_zero_begin;
				end_pos = num_of_zero_begin + num_of_zero;
			}

			val = ((val << 1) | bit);
		}

		uint64_t left = 0;
		for (uint64_t i = 0; i < bit_size; ++i) {
			const uint64_t bit = (val >> (bit_size - i - 1)) & 1;
			left = bit_arrays.at(i).rank(bit, left);
			if (bit) {
				left += this->begin_one.at(i);
			}
		}

		uint64_t rank = begin_pos + k - left + 1;
		return select(val, rank) - 1;
	}


	uint64_t rankLessThan(uint64_t c, uint64_t pos) {
		uint64_t rank_less_than = 0, rank_more_than = 0, rank = 0;
		rankAll(c, 0, pos, rank, rank_less_than, rank_more_than);
		return rank_less_than;
	}


	uint64_t rankMoreThan(uint64_t c, uint64_t pos) {
		uint64_t rank_less_than = 0, rank_more_than = 0, rank = 0;
		rankAll(c, 0, pos, rank, rank_less_than, rank_more_than);
		return rank_more_than;
	}


	void rankAll(uint64_t c, uint64_t begin_pos, uint64_t end_pos, uint64_t &rank, uint64_t &rank_less_than, uint64_t &rank_more_than) {
		if (c >= maximum_element || begin_pos >= size || end_pos > size) {
			rank_less_than = NOTFOUND;
			rank_more_than = NOTFOUND;
			rank           = NOTFOUND;
			return;
		}
		rank_less_than = 0;
		rank_more_than = 0;
		rank = 0;

		if (begin_pos >= end_pos) {
			return;
		}

		vector<uint64_t> more_and_less(2, 0);
		for (uint64_t i = 0; i < bit_size; ++i) {
			const uint64_t bit = (c >> (bit_size - i - 1)) & 1;

			const uint64_t range_bits = end_pos - begin_pos;
			const uint64_t begin_zero = bit_arrays.at(i).rank(0, begin_pos);
			const uint64_t end_zero = bit_arrays.at(i).rank(0, end_pos);

			if (bit) {
				begin_pos += this->begin_one.at(i) - begin_zero;
				end_pos += this->begin_one.at(i) - end_zero;
			} else {
				begin_pos = begin_zero;
				end_pos = end_zero;
			}
			more_and_less.at(bit) += range_bits - (end_pos - begin_pos);
		}

		rank_less_than = more_and_less.at(1);
		rank_more_than = more_and_less.at(0);
		rank = end_pos - begin_pos;
	}


	vector<pair<uint64_t, uint64_t>> topk(uint64_t s, uint64_t e, uint64_t k) {
		assert(s < e);
		vector<pair<uint64_t, uint64_t>> result;

		auto c = [](const tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t> &l, const tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t> &r) {

			if (get<0>(l) != get<0>(r)) {
				return get<0>(l) < get<0>(r);
			}

			if (get<3>(l) != get<3>(r)) {
				return get<3>(l) > get<3>(r);
			}

			if (get<4>(l) != get<4>(r)) {
				return get<4>(l) > get<4>(r);
			}
			return true;
		};

		priority_queue<tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t>, vector<tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t>>, decltype(c)> que(c);
		que.push(make_tuple(e - s, s, e, 0, 0));

		while (not que.empty()) {
			auto element = que.top(); que.pop();
			uint64_t width, left, right, depth, value;
			tie(width, left, right, depth, value) = element;

			if (depth >= this->bit_size) {
				result.emplace_back(make_pair(value, right - left));
				if (result.size() >= k) {
					break;
				}
				continue;
			}


			const uint64_t left0 = this->bit_arrays.at(depth).rank(0, left);
			const uint64_t right0 = this->bit_arrays.at(depth).rank(0, right);
			if (left0 < right0) {
				que.push(make_tuple(right0 - left0, left0, right0, depth + 1, value));
			}


			const uint64_t left1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, left);
			const uint64_t right1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, right);
			if (left1 < right1) {
				que.push(make_tuple(right1 - left1, left1, right1, depth + 1, value | (1 << bit_size - depth - 1)));
			}
		}

		return result;

	};


	vector<tuple<uint64_t, uint64_t, uint64_t>> intersect(uint64_t _s1, uint64_t _e1, uint64_t _s2, uint64_t _e2) {
		assert(_s1 < _e1);
		assert(_s2 < _e2);

		vector<tuple<uint64_t, uint64_t, uint64_t>> intersection;

		queue<tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t>> que;
		que.push(make_tuple(_s1, _e1, _s2, _e2, 0, 0));
		while (not que.empty()) {
			auto e = que.front(); que.pop();
			uint64_t s1, e1, s2, e2, depth, value;
			tie(s1, e1, s2, e2, depth, value) = e;

			if (depth >= this->bit_size) {
				intersection.emplace_back(make_tuple(value, e1 - s1, e2 - s2));
				continue;
			}


			uint64_t s1_0 = this->bit_arrays.at(depth).rank(0, s1);
			uint64_t e1_0 = this->bit_arrays.at(depth).rank(0, e1);
			uint64_t s2_0 = this->bit_arrays.at(depth).rank(0, s2);
			uint64_t e2_0 = this->bit_arrays.at(depth).rank(0, e2);

			if (s1_0 != e1_0 and s2_0 != e2_0) {
				que.push(make_tuple(s1_0, e1_0, s2_0, e2_0, depth + 1, value));
			}


			uint64_t s1_1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, s1);
			uint64_t e1_1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, e1);
			uint64_t s2_1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, s2);
			uint64_t e2_1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, e2);

			if (s1_1 != e1_1 and s2_1 != e2_1) {
				que.push(make_tuple(s1_1, e1_1, s2_1, e2_1, depth + 1, value | (1 << bit_size - depth - 1)));
			}
		}

		return intersection;
	};

private:
	uint64_t get_num_of_bit(uint64_t x) {
		if (x == 0) return 0;
		x--;
		uint64_t bit_num = 0;
		while (x >> bit_num) {
			++bit_num;
		}
		return bit_num;
	}
};

int main() {
	fast;
	int n, q; cin >> n >> q;
	vector<uint64_t> v(n);
	for (auto &x : v)cin >> x;
	DynamicWaveletMatrix dwm(10000000, v);
	while (q--) {
		int ty, l, r;
		cin >> ty >> l >> r;
		if (ty == 0){
			dwm.insert(l, dwm.access(r));
			dwm.erase(r + 1);
		} else if (ty == 1) {
			cout<<dwm.access(dwm.minRange(l,r+1))<<endl;
		} else {
			dwm.update(l,r);
		}
	}
}
accuracy: 1
time_ms: 3330
memory_kb: 38984
final_rank: 20

code_snippet: #include<bits/stdc++.h>
/*
# pragma GCC target("avx2")
# pragma GCC optimize("O3")
# pragma GCC optimize("unroll-loops")
*/
using namespace std;

#define rep(i, l, n) for(int i = (int)(l); i < (int)(n); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()

template<class T> bool chmin(T &a, T b) {if(a > b) {a = b; return true;} return false;}
template<class T> bool chmax(T &a, T b) {if(a < b) {a = b; return true;} return false;}
template<class T> using spq = priority_queue<T, vector<T>, greater<T>>;

//bool -> Yes/No
string answer(const bool b) {return b ? "Yes" : "No";}

void fix(int k) {cout << fixed << setprecision(k);}

const int inf = 2e9;
const long long INF = 2e18;
const long double eps = 1e-12;
int dx[] = {1, 0, -1, 0, 1, 1, -1, -1}, dy[] = {0, -1, 0, 1, 1, -1, 1, -1};

template<class S, 
        S(*op)(S, S), 
        S(*e)(), 
        class F, 
        S(*mapping)(F, S), 
        F(*composition)(F, F), 
        F(*id)()>
struct Implicit_Treap {

private:    
    struct node {
        S val, acc;
        F lazy;
        node *lch, *rch;
        int priority, sz;
        bool rev;
        node(S v, int p) : val(v), priority(p) {
            acc = e(); lazy = id();
            lch = rch = nullptr;
            sz = 1; rev = false;
        }
    };

    static int xorshift() {
        static int x = 295289572, y = 176387826, z = 872153741, w = 916527329;
        int t = (x ^ (x << 13));
        x = y, y = z, z = w;
        return (w = (w ^ (w >> 17)) ^ (t ^ (t >> 7)));
    }

    node *root = nullptr;
    
    int getsize(node *x) {
        return x == nullptr ? 0 : x->sz;
    }

    S getacc(node *x) {
        return x == nullptr ? e() : x->acc;
    }

    node *eval(node *x) {
        if(x == nullptr) return x;
        x->sz = getsize(x->lch) + getsize(x->rch) + 1;
        x->acc = op(op(getacc(x->lch), x->val), getacc(x->rch));
        return x;
    }
    
    node *push(node *x) {
        if(x == nullptr) return x;
        if(x->rev) {
            x->rev = false;
            swap(x->lch, x->rch);
            if(x->lch != nullptr) x->lch->rev ^= 1;
            if(x->rch != nullptr) x->rch->rev ^= 1;
        }
        if(x->lch != nullptr) {
            x->lch->lazy = composition(x->lch->lazy, x->lazy);
            x->lch->acc = mapping(x->lazy, x->lch->acc);
        }
        if(x->rch != nullptr) {
            x->rch->lazy = composition(x->rch->lazy, x->lazy);
            x->rch->acc = mapping(x->lazy, x->rch->acc);
        }
        x->val = mapping(x->lazy, x->val);
        x->lazy = id();
        return eval(x);
    }

    node *merge(node *l, node *r) {
        if(l == nullptr || r == nullptr) {
            return eval(l == nullptr ? r : l);
        }
        push(l);
        push(r);
        if(l->priority > r->priority) {
            l->rch = merge(l->rch, r);
            return eval(l);
        }
        else {
            r->lch = merge(l, r->lch);
            return eval(r);
        }
    }

    pair<node*, node*> split(node *x, int pos) {
        if(x == nullptr) return make_pair(nullptr, nullptr);
        push(x);
        int k = getsize(x->lch) + 1;
        if(pos < k) {
            auto[l, r] = split(x->lch, pos);
            x->lch = r;
            return make_pair(l, eval(x));
        }
        else {
            auto[l, r] = split(x->rch, pos - k);
            x->rch = l;
            return make_pair(eval(x), r);
        }
    }

    node *insert(node *x, int pos, S v) {
        auto[l, r] = split(x, pos);
        node *y = new node(v, xorshift());
        return root = merge(merge(l, y), r);
    }

    node *erase(node *x, int pos) {
        auto[lm, r] = split(x, pos + 1);
        auto[l, m] = split(lm, pos);
        return root = merge(l, r);
    }

    node *get(node *x, int pos) {
        auto[lm, rr] = split(x, pos + 1);
        auto[ll, m] = split(lm, pos);
        node *ret = m;
        root = merge(merge(ll, m), rr);
        return ret;
    }

    node *apply(node *x, int l, int r, F f) {
        auto[ll, mr] = split(x, l);
        auto[m, rr] = split(mr, r - l);
        m->lazy = composition(m->lazy, f);
        m->acc = mapping(f, m->acc);
        return x = merge(ll, merge(m, rr));
    }

    S prod(node *x, int l, int r) {
        auto[ll, mr] = split(x, l);
        auto[m, rr] = split(mr, r - l);
        S ret = m->acc;
        x = merge(ll, merge(m, rr));
        return ret;
    }

    node *reverse(node *x, int l, int r) {
        if(l > r) return x;
        auto[ll, mr] = split(x, l);
        auto[m, rr] = split(mr, r - l);
        m->rev ^= 1;
        return x = merge(ll, merge(m, rr));
    }

    node *rotate(node *x, int l, int m, int r) {
        reverse(x, l, r);
        reverse(x, l, l + r - m);
        reverse(x, l + r - m, r);
        return x;
    }

    vector<S> display(node *x) {
        if(x == nullptr) return vector<S>(0);
        pushdown(x);
        vector<S> ll = display(x->lch);
        ll.emplace_back(x->val);
        vector<S> rr = display(x->rch);
        ll.insert(ll.end(), make_move_iterator(rr.begin()), make_move_iterator(rr.end()));
        return ll;
    }

public:
    Implicit_Treap() {}

    // xを根としたImplicit_Treapを作る
    Implicit_Treap(node *x) {
        root = x;
    }

    Implicit_Treap merge(Implicit_Treap l, Implicit_Treap r) {
        return Implicit_Treap(merge(l.root, r.root));
    }

    pair<Implicit_Treap, Implicit_Treap> split(int pos) {
        auto[lp, rp] = split(root, pos);
        return make_pair(Implicit_Treap(lp), Implicit_Treap(rp));
    }

    // pos番目(0-indexed)の前に挿入する（最後尾はpos==n)
    void insert(int pos, S v) {
        insert(root, pos, v);
    }

    // pos番目(0-indexed)の前にfirst~lastを挿入（最後尾はpos==n)
    template<class Iterator>
    void insert_from_iterator(int pos, Iterator first, Iterator last) {
        for(Iterator itr = first; itr != last; itr++) {
            insert(pos++, *itr);
        }
    }

    void erase(int pos) {
        erase(root, pos);
    }

    void apply(int l, int r, F f) {
        apply(root, l, r, f);
    }

    void apply(int pos, F f) {
        apply(root, pos, pos + 1, f);
    }

    S prod(int l, int r) {
        return prod(root, l, r);
    }

    void reverse(int l, int r) {
        reverse(root, l, r);
    }

    // [l, r)の先頭がmになるように左シフト
    void rotate(int l, int m, int r) {
        rotate(root, l, m, r);
    }

    // 保持しているデータを配列として返す
    vector<S> display() {
        return display(root);
    }

    S operator[](int pos) {
        return get(root, pos)->acc;
    }

    int size() {
        return getsize(root);
    }

};

int op(int a, int b) {return min(a, b);}
int e() {return inf;}
int mapping(int a, int b) {return a == -1 ? b : a;}
int composition(int a, int b) {return b == -1 ? a : b;}
int id() {return -1;}

void main_program() {
    int n, q; cin >> n >> q;
    vector<int> v(n);
    rep(i, 0, n) cin >> v[i];
    Implicit_Treap<int, op, e, int, mapping, composition, id> tr;
    tr.insert_from_iterator(0, all(v));
    while(q--) {
        int t; cin >> t;
        if(t == 0) {
            int l, r; cin >> l >> r;
            tr.rotate(l, r, r + 1);
        }
        else if(t == 1) {
            int l, r; cin >> l >> r;
            cout << tr.prod(l, ++r) << "\n";
        }
        else {
            int x, v; cin >> x >> v;
            tr.apply(x, v);
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t = 1;
    //cin >> t;
    while(t--) main_program();
}
accuracy: 1
time_ms: 430
memory_kb: 16292
final_rank: 12

code_snippet: #include<bits/stdc++.h>
/*
# pragma GCC target("avx2")
# pragma GCC optimize("O3")
# pragma GCC optimize("unroll-loops")
*/
using namespace std;

#define rep(i, l, n) for(int i = (int)(l); i < (int)(n); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()

template<class T> bool chmin(T &a, T b) {if(a > b) {a = b; return true;} return false;}
template<class T> bool chmax(T &a, T b) {if(a < b) {a = b; return true;} return false;}
template<class T> using spq = priority_queue<T, vector<T>, greater<T>>;

//bool -> Yes/No
string answer(const bool b) {return b ? "Yes" : "No";}

void fix(int k) {cout << fixed << setprecision(k);}

const int inf = 2e9;
const long long INF = 2e18;
const long double eps = 1e-12;
int dx[] = {1, 0, -1, 0, 1, 1, -1, -1}, dy[] = {0, -1, 0, 1, 1, -1, 1, -1};

template<class S, 
        S(*op)(S, S), 
        S(*e)(), 
        class F, 
        F(*mapping)(F, S), 
        F(*composition)(F, F), 
        F(*id)()>
struct Implicit_Treap {

private:    
    struct node {
        S val, acc;
        F lazy;
        node *lch, *rch;
        int priority, sz;
        bool rev;
        node(S v, int p) : val(v), priority(p) {
            acc = e(); lazy = id();
            lch = rch = nullptr;
            sz = 1; rev = false;
        }
    };

    static int xorshift() {
        static int x = 295289572, y = 176387826, z = 872153741, w = 916527329;
        int t = (x ^ (x << 13));
        x = y, y = z, z = w;
        return (w = (w ^ (w >> 17)) ^ (t ^ (t >> 7)));
    }

    node *root = nullptr;
    
    int getsize(node *x) {
        return x == nullptr ? 0 : x->sz;
    }

    S getacc(node *x) {
        return x == nullptr ? e() : x->acc;
    }

    node *eval(node *x) {
        if(x == nullptr) return x;
        x->sz = getsize(x->lch) + getsize(x->rch) + 1;
        x->acc = op(op(getacc(x->lch), x->val), getacc(x->rch));
        return x;
    }
    
    node *push(node *x) {
        if(x == nullptr) return x;
        if(x->rev) {
            x->rev = false;
            swap(x->lch, x->rch);
            if(x->lch != nullptr) x->lch->rev ^= 1;
            if(x->rch != nullptr) x->rch->rev ^= 1;
        }
        if(x->lch != nullptr) {
            x->lch->lazy = composition(x->lch->lazy, x->lazy);
            x->lch->acc = mapping(x->lazy, x->lch->acc);
        }
        if(x->rch != nullptr) {
            x->rch->lazy = composition(x->rch->lazy, x->lazy);
            x->rch->acc = mapping(x->lazy, x->rch->acc);
        }
        x->val = mapping(x->lazy, x->val);
        x->lazy = id();
        return eval(x);
    }

    node *merge(node *l, node *r) {
        if(l == nullptr || r == nullptr) {
            return eval(l == nullptr ? r : l);
        }
        push(l);
        push(r);
        if(l->priority > r->priority) {
            l->rch = merge(l->rch, r);
            return eval(l);
        }
        else {
            r->lch = merge(l, r->lch);
            return eval(r);
        }
    }

    pair<node*, node*> split(node *x, int pos) {
        if(x == nullptr) return make_pair(nullptr, nullptr);
        push(x);
        int k = getsize(x->lch) + 1;
        if(pos < k) {
            auto[l, r] = split(x->lch, pos);
            x->lch = r;
            return make_pair(l, eval(x));
        }
        else {
            auto[l, r] = split(x->rch, pos - k);
            x->rch = l;
            return make_pair(eval(x), r);
        }
    }

    node *insert(node *x, int pos, S v) {
        auto[l, r] = split(x, pos);
        node *y = new node(v, xorshift());
        return root = merge(merge(l, y), r);
    }

    node *erase(node *x, int pos) {
        auto[lm, r] = split(x, pos + 1);
        auto[l, m] = split(lm, pos);
        return root = merge(l, r);
    }

    node *get(node *x, int pos) {
        auto[lm, rr] = split(x, pos + 1);
        auto[ll, m] = split(lm, pos);
        node *ret = m;
        root = merge(merge(ll, m), rr);
        return ret;
    }

    node *apply(node *x, int l, int r, F f) {
        auto[ll, mr] = split(x, l);
        auto[m, rr] = split(mr, r - l);
        m->lazy = composition(m->lazy, f);
        m->acc = mapping(f, m->acc);
        return x = merge(ll, merge(m, rr));
    }

    S prod(node *x, int l, int r) {
        auto[ll, mr] = split(x, l);
        auto[m, rr] = split(mr, r - l);
        S ret = m->acc;
        x = merge(ll, merge(m, rr));
        return ret;
    }

    node *reverse(node *x, int l, int r) {
        if(l > r) return x;
        auto[ll, mr] = split(x, l);
        auto[m, rr] = split(mr, r - l);
        m->rev ^= 1;
        return x = merge(ll, merge(m, rr));
    }

    node *rotate(node *x, int l, int m, int r) {
        reverse(x, l, r);
        reverse(x, l, l + r - m);
        reverse(x, l + r - m, r);
        return x;
    }

    vector<S> display(node *x) {
        if(x == nullptr) return vector<S>(0);
        pushdown(x);
        vector<S> ll = display(x->lch);
        ll.emplace_back(x->val);
        vector<S> rr = display(x->rch);
        ll.insert(ll.end(), make_move_iterator(rr.begin()), make_move_iterator(rr.end()));
        return ll;
    }

public:
    Implicit_Treap() {}

    // xを根としたImplicit_Treapを作る
    Implicit_Treap(node *x) {
        root = x;
    }

    Implicit_Treap merge(Implicit_Treap l, Implicit_Treap r) {
        return Implicit_Treap(merge(l.root, r.root));
    }

    pair<Implicit_Treap, Implicit_Treap> split(int pos) {
        auto[lp, rp] = split(root, pos);
        return make_pair(Implicit_Treap(lp), Implicit_Treap(rp));
    }

    // pos番目(0-indexed)の前に挿入する（最後尾はpos==n)
    void insert(int pos, S v) {
        insert(root, pos, v);
    }

    // pos番目(0-indexed)の前にfirst~lastを挿入（最後尾はpos==n)
    template<class Iterator>
    void insert_from_iterator(int pos, Iterator first, Iterator last) {
        for(Iterator itr = first; itr != last; itr++) {
            insert(pos++, *itr);
        }
    }

    void erase(int pos) {
        erase(root, pos);
    }

    void apply(int l, int r, F f) {
        apply(root, l, r, f);
    }

    void apply(int pos, F f) {
        apply(root, pos, pos + 1, f);
    }

    S prod(int l, int r) {
        return prod(root, l, r);
    }

    void reverse(int l, int r) {
        reverse(root, l, r);
    }

    // [l, r)の先頭がmになるように左シフト
    void rotate(int l, int m, int r) {
        rotate(root, l, m, r);
    }

    // 保持しているデータを配列として返す
    vector<S> display() {
        return display(root);
    }

    S operator[](int pos) {
        return get(root, pos)->acc;
    }

    int size() {
        return getsize(root);
    }

};

int op(int a, int b) {return min(a, b);}
int e() {return inf;}
int mapping(int a, int b) {return a == -1 ? b : a;}
int composition(int a, int b) {return b == -1 ? a : b;}
int id() {return -1;}

void main_program() {
    int n, q; cin >> n >> q;
    vector<int> v(n);
    rep(i, 0, n) cin >> v[i];
    Implicit_Treap<int, op, e, int, mapping, composition, id> tr;
    tr.insert_from_iterator(0, all(v));
    while(q--) {
        int t; cin >> t;
        if(t == 0) {
            int l, r; cin >> l >> r;
            tr.rotate(l, r, r + 1);
        }
        else if(t == 1) {
            int l, r; cin >> l >> r;
            cout << tr.prod(l, ++r) << "\n";
        }
        else {
            int x, v; cin >> x >> v;
            tr.apply(x, v);
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t = 1;
    //cin >> t;
    while(t--) main_program();
}
accuracy: 1
time_ms: 420
memory_kb: 16292
final_rank: 11

code_snippet: #include<iostream>  
using namespace std;

struct SplayNode{
    SplayNode *left, *right, *parent;
    int size, value, minimum;

    SplayNode(){
        left = nullptr;
        right = nullptr;
        parent = nullptr;
        size = 1;
    }

    void rotate(){
        SplayNode *pp, *p, *c;
        p = this->parent;
        pp = p->parent;

        if(p->left == this){
            c = this->right;
            this->right = p;
            p->left = c;
        }
        else{
            c = this->left;
            this->left = p;
            p->right = c;
        }
        if(pp && pp->left == p)pp->left = this;
        if(pp && pp->right == p)pp->right = this;
        this->parent = pp;
        p->parent = this;
        if(c)c->parent = p;

        p->update();
        this->update();
    }

    int state(){
        if(!this->parent)return 0;
        if(this->parent->left == this)return 1;
        if(this->parent->right == this)return -1;
        return 0;
    }
    
    void splay(){
        while(this->state() != 0){
            if(this->parent->state() == 0){
                this->rotate();
            }
            else if(this->state() == this->parent->state()){
                this->parent->rotate();
                this->rotate();
            }else{
                this->rotate();
                this->rotate();
            }
        }
    }
    
    void update(){
        this->size = 1;
        this->minimum = this->value;
        if(this->left){
            this->size += this->left->size;
            this->minimum = min(this->minimum, this->left->minimum);
        }
        if(this->right){
            this->size += this->right->size;
            this->minimum = min(this->minimum, this->right->minimum);
        }
    }    
};


SplayNode *get(int ind, SplayNode *root){
    SplayNode *now = root;
    while(true){
        int lsize = now->left ? now->left->size : 0;
        if(ind < lsize){
            now = now->left;
        }
        if(ind == lsize){
            now->splay();
            return now;
        }
        if(ind > lsize){
            now = now->right;
            ind = ind - lsize - 1;
        }
    }
}

SplayNode *merge(SplayNode *lroot, SplayNode *rroot){
    if(!lroot)return rroot;
    if(!rroot)return lroot;
    lroot = get(lroot->size-1, lroot);
    lroot->right = rroot;
    rroot->parent = lroot;
    lroot->update();
    return lroot;
}

pair<SplayNode*, SplayNode*> split(int left_cnt, SplayNode *root){
    if(left_cnt == 0)return {nullptr, root};
    if(left_cnt == root->size)return {root, nullptr};
    root = get(left_cnt, root);
    SplayNode *lroot, *rroot;
    lroot = root->left;
    rroot = root;
    rroot->left = nullptr;
    lroot->parent = nullptr;
    rroot->update();
    return {lroot, rroot};
}

SplayNode *insert(int ind, SplayNode *node, SplayNode *root){
    auto trees = split(ind, root);
    SplayNode *lroot = trees.first;
    SplayNode *rroot = trees.second;
    return merge(merge(lroot, node), rroot);
}

pair<SplayNode*, SplayNode*> remove(int ind, SplayNode *root){
    root = get(ind, root);
    SplayNode *lroot = root->left;
    SplayNode *rroot = root->right;
    if(lroot)lroot->parent = nullptr;
    if(rroot)rroot->parent = nullptr;
    root->left = nullptr;
    root->right = nullptr;
    root->update();
    return {merge(lroot, rroot), root};
}

SplayNode *shift(int l, int r, SplayNode *root){
    auto trees = remove(r, root);
    root = trees.first;
    SplayNode *node = trees.second;
    return insert(l, node, root);
}

pair<SplayNode*, int> rmq(int l, int r, SplayNode *root){
    SplayNode *lroot, *croot, *rroot;
    auto tmp = split(r+1, root);
    rroot = tmp.second;
    tmp = split(l, tmp.first);
    lroot = tmp.first;
    croot = tmp.second;
    int ans = croot->minimum;
    return {merge(merge(lroot, croot), rroot), ans};
}

int main(){
    int n,q;
    cin >> n >> q;
    int vecsize = 0;
    SplayNode node[n];
    for(int i = 0; i < n-1; i++){
        node[i].parent = &node[i+1];
        node[i+1].left = &node[i];
        node[i+1].update();
    }
    for(int i = 0; i < n; i++){
        cin >> node[i].value;
        node[i].update();
    }
    SplayNode *root = &node[n-1];
    for(int i = 0; i < q; i++){
        int ord,x;
        cin >> ord;
        if(ord == 0){
            int l, r;
            cin >> l >> r;
            root = shift(l, r, root);
        }
        if(ord == 1){
            int l, r;
            cin >> l >> r;
            auto tmp = rmq(l, r, root);
            root = tmp.first;
            cout << tmp.second << endl;
        }
        if(ord == 2){
            int pos, val;
            cin >> pos >> val;
            root = get(pos, root);
            root->value = val;
            root->update();
        }
    }
}
accuracy: 1
time_ms: 310
memory_kb: 11460
final_rank: 1

code_snippet: // ================================================
//
// RMQ
// https://onlinejudge.u-aizu.ac.jp/challenges/sources/UOA/UAPC/1508
//
// [SplayTree]
//
// ================================================

#include <bits/stdc++.h>
using namespace std;

struct SplayNode {
    SplayNode *left, *right, *parent;
    int size, value, minimum;
    SplayNode() {
        left = nullptr;
        right = nullptr;
        parent = nullptr;
        size = 1;
    }

    void rotate() {
        SplayNode *pp, *p, *c;
        p = this->parent;
        pp = p->parent;

        if (p->left == this) {
            c = this->right;
            this->right = p;
            p->left = c;
        } else {
            c = this->left;
            this->left = p;
            p->right = c;
        }

        if (pp and pp->left == p) pp->left = this;
        if (pp and pp->right == p) pp->right = this;
        this->parent = pp;
        p->parent = this;
        if (c) c->parent = p;

        p->update();
        this->update();
    }

    int state() {
        if (not this->parent) return 0;
        if (this->parent->left == this) return 1;
        if (this->parent->right == this) return -1;
        return 0;
    }

    void splay() {
        while (this->state() != 0) {
            if (this->parent->state() == 0) {
                this->rotate();
            } else if (this->state() == this->parent->state()) {
                this->parent->rotate();
                this->rotate();
            } else {
                this->rotate();
                this->rotate();
            }
        }
    }

    void update() {
        this->size = 1;
        this->minimum = this->value;
        if (this->left) {
            this->size += this->left->size;
            this->minimum = min(this->minimum, this->left->minimum);
        }
        if (this->right) {
            this->size += this->right->size;
            this->minimum = min(this->minimum, this->right->minimum);
        }
    }
};

using SN = SplayNode;

SN *get(int pos, SN *root) {
    SN *now = root;
    while (true) {
        int lsize = now->left ? now->left->size : 0;
        if (pos < lsize) {
            now = now->left;
        }
        if (pos == lsize) {
            now->splay();
            return now;
        }
        if (pos > lsize) {
            now = now->right;
            pos = pos - lsize - 1;
        }
    }
}

SN *merge(SN *lroot, SN *rroot) {
    if (not lroot) return rroot;
    if (not rroot) return lroot;
    // 左木の右端を取得
    lroot = get(lroot->size - 1, lroot);
    // 左木野右端に右木を結合
    lroot->right = rroot;
    rroot->parent = lroot;
    lroot->update();
    return lroot;
};

pair<SN *, SN *> split(int pos, SN *root) {
    if (pos == 0) return {nullptr, root};
    if (pos == root->size) return {root, nullptr};
    // 分割点を取得
    root = get(pos, root);
    SN *lroot = root->left, *rroot = root;
    // 双方向に分離
    rroot->left = nullptr;
    lroot->parent = nullptr;
    rroot->update();
    return {lroot, rroot};
};

SN *insert(int pos, SN *node, SN *root) {
    SN *lroot, *rroot;
    tie(lroot, rroot) = split(pos, root);
    return merge(merge(lroot, node), rroot);
};

pair<SN *, SN *> remove(int pos, SN *root) {
    root = get(pos, root);
    SN *lroot = root->left;
    SN *rroot = root->right;
    if (lroot) lroot->parent = nullptr;
    if (rroot) rroot->parent = nullptr;
    root->left = nullptr;
    root->right = nullptr;
    root->update();
    return {merge(lroot, rroot), root};
};

SN *shift(int l, int r, SN *root) {
    SN *node;
    tie(root, node) = remove(r, root);
    return insert(l, node, root);
}

pair<SN *, int> rmq(int l, int r, SN *root) {
    SN *lroot, *rroot, *croot;
    tie(root, rroot) = split(r + 1, root);
    tie(lroot, croot) = split(l, root);
    int ans = croot->minimum;
    return {merge(merge(lroot, croot), rroot), ans};
}

SN nodes[220000];

int main() {
    int n, q;
    cin >> n >> q;

    for (int i = 0; i < n - 1; i++) {
        nodes[i].parent = &nodes[i + 1];
        nodes[i + 1].left = &nodes[i];
        nodes[i + 1].update();
    }

    for (int i = 0; i < n; i++) {
        cin >> nodes[i].value;
        nodes[i].update();
    }

    SN *root = &nodes[n - 1];

    for (int i = 0; i < q; i++) {
        int cmd, l, r, pos, val;
        cin >> cmd;
        if (cmd == 0) { // shift
            cin >> l >> r;
            root = shift(l, r, root);
        } else if (cmd == 1) { // rmq
            cin >> l >> r;
            auto tmp = rmq(l, r, root);
            root = tmp.first;
            cout << tmp.second << endl;
        } else if (cmd == 2) { // set
            cin >> pos >> val;
            root = get(pos, root);
            root->value = val;
            root->update();
        }
    }
}

// ================================================
accuracy: 1
time_ms: 310
memory_kb: 12208
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i = 0; i < (n); ++i)
#define repp(i,n) for(int i = 1; i <= (n); ++i)
#define drep(i,n) for(int i = (n)-1; i >= 0; --i)
#define srep(i,s,t) for (int i = s; i < (t); ++i)
#define rng(a) a.begin(),a.end()
#define rrng(a) a.rbegin(),a.rend()
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define em emplace
#define pob pop_back
#define sz(x) (int)(x).size()
#define pcnt __builtin_popcountll
#define koulet srand((unsigned)clock()+(unsigned)time(NULL));
#define newline puts("")
#define vc vector
#define stoi stoll 
template<class T> using vv = vc<vc<T>>;
template<class T> using PQ = priority_queue<T,vc<T>,greater<T>>;
using uint = unsigned; using ull = unsigned long long;
using i128=__int128 ;
using vi = vc<int>; using vvi = vv<int>; using vvvi = vv<vi>;
using ll = long long; using vl = vc<ll>; using vvl = vv<ll>; using vvvl = vv<vl>;
using P = pair<int,int>; using vp = vc<P>; using vvp = vv<P>; using LP = pair<ll,ll>;
using vs = vc<string>; using vb=vc<bool> ; using vlp = vc<LP> ; 
int geti(){int x;scanf("%d",&x);return x;}
vi pm(int n, int s=0) { vi a(n); iota(rng(a),s); return a;}
template<class T1,class T2>istream& operator>>(istream&i,pair<T1,T2>&v){return i>>v.fi>>v.se;}
template<class T1,class T2>ostream& operator<<(ostream&o,const pair<T1,T2>&v){return o<<v.fi<<","<<v.se;}
template<class T>istream& operator>>(istream&i,vc<T>&v){rep(j,sz(v))i>>v[j];return i;}
template<class T>string join(const T&v,const string&d=""){stringstream s;rep(i,sz(v))(i?s<<d:s)<<v[i];return s.str();}
template<class T>ostream& operator<<(ostream&o,const vc<T>&v){if(sz(v))o<<join(v," ");return o;}
template<class T>void vin(vc<T>&a){int n;cin>>n;a=vc<T>(n);cin>>a;}
template<class T>void vin(vv<T>&a){int n,m;cin>>n>>m;a=vv<T>(n,vc<T>(m));cin>>a;}
template<class T1,class T2>void operator--(pair<T1,T2>&a,int){a.fi--;a.se--;}
template<class T1,class T2>void operator++(pair<T1,T2>&a,int){a.fi++;a.se++;}
template<class T>void operator--(vc<T>&a,int){for(T&x:a)x--;}
template<class T>void operator++(vc<T>&a,int){for(T&x:a)x++;}
template<class T>void operator+=(vc<T>&a,T b){for(T&x:a)x+=b;}
template<class T>void operator-=(vc<T>&a,T b){for(T&x:a)x-=b;}
template<class T>void operator*=(vc<T>&a,T b){for(T&x:a)x*=b;}
template<class T>void operator/=(vc<T>&a,T b){for(T&x:a)x/=b;}
template<class T>void operator+=(vc<T>&a,const vc<T>&b){a.insert(a.end(),rng(b));}
template<class T1,class T2>pair<T1,T2>operator+(const pair<T1,T2>&a,const pair<T1,T2>&b){return {a.fi+b.fi,a.se+b.se};}
template<class T1,class T2>pair<T1,T2>operator-(const pair<T1,T2>&a,const pair<T1,T2>&b){return {a.fi-b.fi,a.se-b.se};}
template<class T>pair<T,T>operator*(const pair<T,T>&a,T b){return {a.fi*b,a.se*b};}
template<class T1,class T2>bool mins(T1& x,const T2&y){if(y<x){x=y;return true;}else return false;}
template<class T1,class T2>bool maxs(T1& x,const T2&y){if(x<y){x=y;return true;}else return false;}
template<class T>T min(const vc<T>&a){return *min_element(rng(a));}
template<class T>T max(const vc<T>&a){return *max_element(rng(a));}
template<class Tx,class Ty>Tx dup(Tx x, Ty y){return (x+y-1)/y;}
template<class T>ll suma(const vc<T>&a){ll s=0;for(auto&&x:a)s+=x;return s;}
template<class T>ll suma(const vv<T>&a){ll s=0;for(auto&&x:a)s+=suma(x);return s;}
template<class T>void uni(T&a){sort(rng(a));a.erase(unique(rng(a)),a.end());}
template<class T>void prepend(vc<T>&a,const T&x){a.insert(a.begin(),x);}
template<typename T>T floor(T a, T b){T r=(a%b+b)%b;return (a-r)/b;}
template<typename T>T ceil(T a, T b){return floor(a+b-1,b);}
template<typename T>vc<T> cumsum(vc<T> &a,int off=1){int N=sz(a);vc<T>B(N+1);rep(i, N)B[i+1]=a[i]+B[i];if(off==0)B.erase(B.begin());return B;}
const double eps = 1e-10; // a<b -> a<b-eps
const ll LINF = 1001002003004005006ll;
const int INF = 1001001001;
template <class T>
constexpr T infty = 0;
template <>
constexpr int infty<int> = 1'010'000'000;
template <>
constexpr ll infty<ll> = 2'020'000'000'000'000'000;
template <>
constexpr uint infty<uint> = infty<int>;
template <>
constexpr ull infty<ull> = infty<ll>;
template <>
constexpr i128 infty<i128> = i128(infty<ll>) * 2'000'000'000'000'000'000;
template <>
constexpr double infty<double> = infty<ll>;
template <>
constexpr long double infty<long double> = infty<ll>;
// (0, 1, 2, 3, 4) -> (-1, 0, 1, 1, 2)
int topbit(int x) { return (x == 0 ? -1 : 31 - __builtin_clz(x)); }
int topbit(uint x) { return (x == 0 ? -1 : 31 - __builtin_clz(x)); }
int topbit(ll x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
int topbit(ull x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
// (0, 1, 2, 3, 4) -> (-1, 0, 1, 0, 2)
int lowbit(int x) { return (x == 0 ? -1 : __builtin_ctz(x)); }
int lowbit(uint x) { return (x == 0 ? -1 : __builtin_ctz(x)); }
int lowbit(ll x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }
int lowbit(ull x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }
#define dame { puts("-1"); return 0 ;}
#define yes { puts("Yes"); return 0 ;}
#define no { puts("No"); return 0 ;}
#define rtn(x) { cout<<(x)<<endl;} // flush!
#define yn {puts("Yes");}else{puts("No");}
ll c2(ll n) { return n*(n-1)>>1;}
template<typename T>void rot(T& a,int i){rotate(a.begin(),a.begin()+(i),a.end());}// i回シフト
template<typename T>void rot(vv<T>& a){int h=sz(a),w=sz(a[0]);vv<T> p(w,vc<T>(h));swap(a,p);rep(i,h)rep(j,w)a[j][h-1-i]=p[i][j];}
void rot(vc<string>& a){int h=sz(a),w=sz(a[0]);vc<string> p(w,string(h,'?'));swap(a,p);rep(i,h)rep(j,w)a[j][h-1-i]=p[i][j];}
//90度時計回り回転
const int dx[] = {-1,0,1,0,1,1,-1,-1,}, dy[] = {0,-1,0,1,1,-1,1,-1}; //^<v>↘︎
//^, <, v, >, ↘︎, ↙︎, ↗︎, ↖︎ 

template <typename ActedMonoid, bool PERSISTENT=false>
struct RBST_ActedMonoid {
  using Monoid_X = typename ActedMonoid::Monoid_X;
  using Monoid_A = typename ActedMonoid::Monoid_A;
  using X = typename Monoid_X::value_type;
  using A = typename Monoid_A::value_type;

  struct Node {
    Node *l, *r;
    X x, prod; // lazy, rev 反映済
    A lazy;
    uint size;
    bool rev;
  };

  Node *pool;
  const int NODES;
  int pid;
  using np = Node *;

  RBST_ActedMonoid(int NODES) : NODES(NODES), pid(0) { pool = new Node[NODES]; }
  ~RBST_ActedMonoid() { delete[] pool; }

  void reset() { pid = 0; }

  np new_node(const X &x) {
    pool[pid].l = pool[pid].r = nullptr;
    pool[pid].x = x;
    pool[pid].prod = x;
    pool[pid].lazy = Monoid_A::unit();
    pool[pid].size = 1;
    pool[pid].rev = 0;
    return &(pool[pid++]);
  }

  np new_node(const vc<X> &dat) {
    auto dfs = [&](auto &dfs, uint l, uint r) -> np {
      if (l == r) return nullptr;
      if (r == l + 1) return new_node(dat[l]);
      uint m = (l + r) / 2;
      np l_root = dfs(dfs, l, m);
      np r_root = dfs(dfs, m + 1, r);
      np root = new_node(dat[m]);
      root->l = l_root, root->r = r_root;
      update(root);
      return root;
    };
    return dfs(dfs, 0, sz(dat));
  }

  np copy_node(np &n) {
    if (!n || !PERSISTENT) return n;
    pool[pid].l = n->l, pool[pid].r = n->r;
    pool[pid].x = n->x;
    pool[pid].prod = n->prod;
    pool[pid].lazy = n->lazy;
    pool[pid].size = n->size;
    pool[pid].rev = n->rev;
    return &(pool[pid++]);
  }

  np merge(np l_root, np r_root) { return merge_rec(l_root, r_root); }
  np merge3(np a, np b, np c) { return merge(merge(a, b), c); }
  np merge4(np a, np b, np c, np d) { return merge(merge(merge(a, b), c), d); }
  pair<np, np> split(np root, uint k) {
    if (!root) {
      assert(k == 0);
      return {nullptr, nullptr};
    }
    assert(0 <= k && k <= root->size);
    return split_rec(root, k);
  }
  tuple<np, np, np> split3(np root, uint l, uint r) {
    np nm, nr;
    tie(root, nr) = split(root, r);
    tie(root, nm) = split(root, l);
    return {root, nm, nr};
  }
  tuple<np, np, np, np> split4(np root, uint i, uint j, uint k) {
    np d;
    tie(root, d) = split(root, k);
    auto [a, b, c] = split3(root, i, j);
    return {a, b, c, d};
  }

  X prod(np root, uint l, uint r) {
    if (l == r) return Monoid_X::unit();
    return prod_rec(root, l, r, false);
  }
  X prod(np root) { return (root ? root->prod : Monoid_X::unit()); }

  np reverse(np root, uint l, uint r) {
    assert(Monoid_X::commute);
    assert(0 <= l && l <= r && r <= root->size);
    if (r - l <= 1) return root;
    auto [nl, nm, nr] = split3(root, l, r);
    nm->rev ^= 1;
    swap(nm->l, nm->r);
    return merge3(nl, nm, nr);
  }

  np apply(np root, uint l, uint r, const A a) {
    assert(0 <= l && l <= r && r <= root->size);
    return apply_rec(root, l, r, a);
  }
  np apply(np root, const A a) {
    if (!root) return root;
    return apply_rec(root, 0, root->size, a);
  }

  np set(np root, uint k, const X &x) { return set_rec(root, k, x); }
  np multiply(np root, uint k, const X &x) { return multiply_rec(root, k, x); }
  X get(np root, uint k) { return get_rec(root, k, false, Monoid_A::unit()); }

  vc<X> get_all(np root) {
    vc<X> res;
    auto dfs = [&](auto &dfs, np root, bool rev, A lazy) -> void {
      if (!root) return;
      X me = ActedMonoid::act(root->x, lazy, 1);
      lazy = Monoid_A::op(root->lazy, lazy);
      dfs(dfs, (rev ? root->r : root->l), rev ^ root->rev, lazy);
      res.eb(me);
      dfs(dfs, (rev ? root->l : root->r), rev ^ root->rev, lazy);
    };
    dfs(dfs, root, 0, Monoid_A::unit());
    return res;
  }

  template <typename F>
  pair<np, np> split_max_right(np root, const F check) {
    assert(check(Monoid_X::unit()));
    X x = Monoid_X::unit();
    return split_max_right_rec(root, check, x);
  }

private:
  inline uint xor128() {
    static uint x = 123456789;
    static uint y = 362436069;
    static uint z = 521288629;
    static uint w = 88675123;
    uint t = x ^ (x << 11);
    x = y;
    y = z;
    z = w;
    return w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
  }

  void prop(np c) {
    // 自身をコピーする必要はない。
    // 子をコピーする必要がある。複数の親を持つ可能性があるため。
    bool bl_lazy = (c->lazy != Monoid_A::unit());
    bool bl_rev = c->rev;
    if (bl_lazy || bl_rev) {
      c->l = copy_node(c->l);
      c->r = copy_node(c->r);
    }
    if (c->lazy != Monoid_A::unit()) {
      if (c->l) {
        c->l->x = ActedMonoid::act(c->l->x, c->lazy, 1);
        c->l->prod = ActedMonoid::act(c->l->prod, c->lazy, c->l->size);
        c->l->lazy = Monoid_A::op(c->l->lazy, c->lazy);
      }
      if (c->r) {
        c->r->x = ActedMonoid::act(c->r->x, c->lazy, 1);
        c->r->prod = ActedMonoid::act(c->r->prod, c->lazy, c->r->size);
        c->r->lazy = Monoid_A::op(c->r->lazy, c->lazy);
      }
      c->lazy = Monoid_A::unit();
    }
    if (c->rev) {
      if (c->l) {
        c->l->rev ^= 1;
        swap(c->l->l, c->l->r);
      }
      if (c->r) {
        c->r->rev ^= 1;
        swap(c->r->l, c->r->r);
      }
      c->rev = 0;
    }
  }

  void update(np c) {
    // データを保ったまま正常化するだけなので、コピー不要
    c->size = 1;
    c->prod = c->x;
    if (c->l) {
      c->size += c->l->size;
      c->prod = Monoid_X::op(c->l->prod, c->prod);
    }
    if (c->r) {
      c->size += c->r->size;
      c->prod = Monoid_X::op(c->prod, c->r->prod);
    }
  }

  np merge_rec(np l_root, np r_root) {
    if (!l_root) return r_root;
    if (!r_root) return l_root;
    uint sl = l_root->size, sr = r_root->size;
    if (xor128() % (sl + sr) < sl) {
      prop(l_root);
      l_root = copy_node(l_root);
      l_root->r = merge_rec(l_root->r, r_root);
      update(l_root);
      return l_root;
    }
    prop(r_root);
    r_root = copy_node(r_root);
    r_root->l = merge_rec(l_root, r_root->l);
    update(r_root);
    return r_root;
  }

  pair<np, np> split_rec(np root, uint k) {
    if (!root) return {nullptr, nullptr};
    prop(root);
    uint sl = (root->l ? root->l->size : 0);
    if (k <= sl) {
      auto [nl, nr] = split_rec(root->l, k);
      root = copy_node(root);
      root->l = nr;
      update(root);
      return {nl, root};
    }
    auto [nl, nr] = split_rec(root->r, k - (1 + sl));
    root = copy_node(root);
    root->r = nl;
    update(root);
    return {root, nr};
  }

  np set_rec(np root, uint k, const X &x) {
    if (!root) return root;
    prop(root);
    uint sl = (root->l ? root->l->size : 0);
    if (k < sl) {
      root = copy_node(root);
      root->l = set_rec(root->l, k, x);
      update(root);
      return root;
    }
    if (k == sl) {
      root = copy_node(root);
      root->x = x;
      update(root);
      return root;
    }
    root = copy_node(root);
    root->r = set_rec(root->r, k - (1 + sl), x);
    update(root);
    return root;
  }

  np multiply_rec(np root, uint k, const X &x) {
    if (!root) return root;
    prop(root);
    uint sl = (root->l ? root->l->size : 0);
    if (k < sl) {
      root = copy_node(root);
      root->l = multiply_rec(root->l, k, x);
      update(root);
      return root;
    }
    if (k == sl) {
      root = copy_node(root);
      root->x = Monoid_X::op(root->x, x);
      update(root);
      return root;
    }
    root = copy_node(root);
    root->r = multiply_rec(root->r, k - (1 + sl), x);
    update(root);
    return root;
  }

  X prod_rec(np root, uint l, uint r, bool rev) {
    if (l == 0 && r == root->size) { return root->prod; }
    np left = (rev ? root->r : root->l);
    np right = (rev ? root->l : root->r);
    uint sl = (left ? left->size : 0);
    X res = Monoid_X::unit();
    if (l < sl) {
      X y = prod_rec(left, l, min(r, sl), rev ^ root->rev);
      res = Monoid_X::op(res, ActedMonoid::act(y, root->lazy, min(r, sl) - l));
    }
    if (l <= sl && sl < r) res = Monoid_X::op(res, root->x);
    uint k = 1 + sl;
    if (k < r) {
      X y = prod_rec(right, max(k, l) - k, r - k, rev ^ root->rev);
      res = Monoid_X::op(res, ActedMonoid::act(y, root->lazy, r - max(k, l)));
    }
    return res;
  }

  X get_rec(np root, uint k, bool rev, A lazy) {
    np left = (rev ? root->r : root->l);
    np right = (rev ? root->l : root->r);
    uint sl = (left ? left->size : 0);
    if (k == sl) return ActedMonoid::act(root->x, lazy, 1);
    lazy = Monoid_A::op(root->lazy, lazy);
    rev ^= root->rev;
    if (k < sl) return get_rec(left, k, rev, lazy);
    return get_rec(right, k - (1 + sl), rev, lazy);
  }

  np apply_rec(np root, uint l, uint r, const A &a) {
    prop(root);
    root = copy_node(root);
    if (l == 0 && r == root->size) {
      root->x = ActedMonoid::act(root->x, a, 1);
      root->prod = ActedMonoid::act(root->prod, a, root->size);
      root->lazy = a;
      return root;
    }
    uint sl = (root->l ? root->l->size : 0);
    if (l < sl) root->l = apply_rec(root->l, l, min(r, sl), a);
    if (l <= sl && sl < r) root->x = ActedMonoid::act(root->x, a, 1);
    uint k = 1 + sl;
    if (k < r) root->r = apply_rec(root->r, max(k, l) - k, r - k, a);
    update(root);
    return root;
  }

  template <typename F>
  pair<np, np> split_max_right_rec(np root, F check, X &x) {
    if (!root) return {nullptr, nullptr};
    prop(root);
    root = copy_node(root);
    X y = Monoid_X::op(x, root->prod);
    if (check(y)) {
      x = y;
      return {root, nullptr};
    }
    np left = root->l, right = root->r;
    if (left) {
      X y = Monoid_X::op(x, root->l->prod);
      if (!check(y)) {
        auto [n1, n2] = split_max_right_rec(left, check, x);
        root->l = n2;
        update(root);
        return {n1, root};
      }
      x = y;
    }
    y = Monoid_X::op(x, root->x);
    if (!check(y)) {
      root->l = nullptr;
      update(root);
      return {left, root};
    }
    x = y;
    auto [n1, n2] = split_max_right_rec(right, check, x);
    root->r = n1;
    update(root);
    return {root, n2};
  }
};

template <typename E>
struct Monoid_Min {
  using X = E;
  using value_type = X;
  static constexpr X op(const X &x, const X &y) noexcept { return min(x, y); }
  static constexpr X unit() { return infty<E>; }
  static constexpr bool commute = true;
};

template <typename X, int none_val>
struct Monoid_Assign {
  using value_type = X;
  static X op(X x, X y) { return (y == X(none_val) ? x : y); }
  static constexpr X unit() { return X(none_val); }
  static constexpr bool commute = false;
};

template <typename E, E none_val>
struct ActedMonoid_Min_Assign {
  using Monoid_X = Monoid_Min<E>;
  using Monoid_A = Monoid_Assign<E, none_val>;
  using X = typename Monoid_X::value_type;
  using A = typename Monoid_A::value_type;
  static constexpr X act(const X &x, const A &a, const ll &size) {
    return (a == none_val ? x : a);
  }
};

int main() {
	int n, q;cin>>n>>q; 
	RBST_ActedMonoid<ActedMonoid_Min_Assign<int,-1>> t(n) ;
	vi a(n) ;cin>>a;
	auto root=t.new_node(a) ;
	while(q--){
		int op;cin>>op;
		int l, r;cin>>l>>r ;
		if(op == 0){
			auto[a,b,c,d]=t.split4(root, l,r,r+1) ;
			root=t.merge4(a,c,b,d) ;
		}
		if(op == 1){
			cout << t.prod(root, l, r+1) <<endl;
		}
		if(op == 2){
			t.set(root, l, r) ;
		}
	}





	


  return 0;
}
accuracy: 1
time_ms: 310
memory_kb: 11668
final_rank: 3

code_snippet: ﻿// ### test.cpp ###
#include <bits/stdc++.h>
#ifdef __DEBUG_VECTOR
namespace for_debugging{
    struct subscript_and_location{
        int sub;
        std::source_location loc;
        subscript_and_location(int sub_,std::source_location loc_=std::source_location::current()){
            sub=sub_;
            loc=loc_;
        }
        void check_out_of_range(size_t sz){
            if(sub<0||(int)sz<=sub){
                std::clog << loc.file_name() << ":(" << loc.line() << ":" << loc.column() << "):" << loc.function_name() << std::endl;
                std::clog << "out of range: subscript = " << sub << ", vector_size = " << sz << std::endl;
                exit(EXIT_FAILURE);
            }
        }
    };
}
namespace std{
    template<class T,class Allocator=std::allocator<T>> class vector_for_debugging:public std::vector<T,Allocator>{
        using std::vector<T,Allocator>::vector;
        public:
            [[nodiscard]] constexpr std::vector<T,Allocator>::reference operator[](for_debugging::subscript_and_location n) noexcept(!std::is_same<T,bool>::value){
                n.check_out_of_range(this->size());
                return std::vector<T,Allocator>::operator[](n.sub);
            }
            [[nodiscard]] constexpr std::vector<T,Allocator>::const_reference operator[](for_debugging::subscript_and_location n) const noexcept(!std::is_same<T,bool>::value){
                n.check_out_of_range(this->size());
                return std::vector<T,Allocator>::operator[](n.sub);
            }
    };
    namespace pmr{
        template<class T> using vector_for_debugging=std::vector_for_debugging<T,std::pmr::polymorphic_allocator<T>>;
    }
}
#define vector vector_for_debugging
#endif
using namespace std;
using ll = long long;
using ull = unsigned long long;
using sll = __int128_t;
using db = double;
using Pr = pair<ll, ll>;
using Pd = pair<double, double>;
using vi = vector<int>;
using vs = vector<string>;
using vc = vector<char>;
using vl = vector<ll>;
using vb = vector<bool>;
using vd = vector<double>;
using vp = vector<Pr>;
using vpd = vector<Pd>;
using vvi = vector<vector<int>>;
using vvc = vector<vector<char>>;
using vvl = vector<vector<ll>>;
using vvp = vector<vector<Pr>>;
using vvb = vector<vector<bool>>;
using vvd = vector<vector<double>>;
using vvs = vector<vector<string>>;
using vvvi = vector<vector<vector<int>>>;
using vvvl = vector<vector<vector<ll>>>;
using vvvb = vector<vector<vector<bool>>>;
using vvvd = vector<vector<vector<double>>>;
using t3 = tuple<ll,ll,ll>;
istream& operator>>(istream &is, t3 &t) { is>>get<0>(t)>>get<1>(t)>>get<2>(t); return is; }
ostream& operator<<(ostream& os, const t3& t) { os<<"("<<get<0>(t)<<','<<get<1>(t)<<','<<get<2>(t)<<")"; return os; }
using t3d = tuple<db,db,db>;
using t4 = tuple<ll,ll,ll,ll>;
istream& operator>>(istream &is, t4 &t) { is>>get<0>(t)>>get<1>(t)>>get<2>(t)>>get<3>(t); return is; }
ostream& operator<<(ostream& os, const t4& t) { os<<"("<<get<0>(t)<<','<<get<1>(t)<<','<<get<2>(t)<<','<<get<3>(t)<<")"; return os; }
using vt3 = vector<t3>;
using vt3d = vector<t3d>;
using vt4 = vector<t4>;
using vvt3 = vector<vector<t3>>;
using vvt3d = vector<vector<t3d>>;
using vvt4 = vector<vector<t4>>;
using pq = priority_queue<Pr,vector<Pr>,greater<Pr>>;
using cl = complex<ll>;
using cd = complex<double>;
#define rep(i, N) for (ll i=0; i<(ll)(N); ++i)
#define repr(i, N) for (ll i = (ll)(N) - 1; i >= 0; --i)
#define repk(i, k, N) for (ll i = k; i < (ll)(N); ++i)
#define rep1(i, N) for (ll i=1; i<(ll)(N+1); ++i)
#define rep1r(i, N) for (ll i=(ll)(N); i>0; i--)
#define all(v) (v).begin(), (v).end()
#define allr(v) (v).rbegin(), (v).rend()
#define SIZE(v) (ll)((v).size())
#define PYes {puts("Yes"); exit(0);}
#define PNo {puts("No"); exit(0);}
#define PFi {puts("First"); exit(0);}
#define PSe {puts("Second"); exit(0);}
#define Pm0 {puts("0"); exit(0);}
#define Pm1 {puts("-1"); exit(0);}
#define INT(...) int __VA_ARGS__; in(__VA_ARGS__)
#define INTM(...) int __VA_ARGS__; inm(__VA_ARGS__)
#define LONG(...) ll __VA_ARGS__; in(__VA_ARGS__)
#define LONGM(...) ll __VA_ARGS__; inm(__VA_ARGS__)
#define DOUBLE(...) double __VA_ARGS__; in(__VA_ARGS__)
#define CHAR(...) char __VA_ARGS__; in(__VA_ARGS__)
#define STRING(...) string __VA_ARGS__; in(__VA_ARGS__)
#define VI(ivec, n) vi ivec(n); input_ivec(ivec, n)
#define VIM(ivec, n) vi ivec(n); input_ivecm(ivec, n)
#define VL(lvec, n) vl lvec(n); input_lvec(lvec, n)
#define VLM(lvec, n) vl lvec(n); input_lvecm(lvec, n)
#define VL2(lvec1, lvec2, n) vl lvec1(n), lvec2(n); input_lvec12(lvec1, lvec2, n)
#define VL2M(lvec1, lvec2, n) vl lvec1(n), lvec2(n); input_lvec12m(lvec1, lvec2, n)
#define VC(cvec, n) vc cvec(n); input_cvec(cvec, n)
#define VS(svec, n) vs svec(n); input_svec(svec, n)
#define VD(dvec, n) vd dvec(n); input_dvec(dvec, n)
#define VP(pvec, n) vp pvec(n); input_pvec(pvec, n)
#define VPD(pvec, n) vpd pvec(n); input_pvecd(pvec, n)
#define VPM(pvec, n) vp pvec(n); input_pvecm(pvec, n)
#define VVI(ivec2, h, w) vvi ivec2(h, vi(w)); input_ivec2(ivec2, h, w)
#define VVL(lvec2, h, w) vvl lvec2(h, vl(w)); input_lvec2(lvec2, h, w)
#define VVLM(lvec2, h, w) vvl lvec2(h, vl(w)); input_lvec2m(lvec2, h, w)
#define VVC(cvec2, h, w) vvc cvec2(h, vc(w)); input_cvec2(cvec2, h, w)
#define uset unordered_set
#define umap unordered_map
inline int pcnt(ll s, ll n=-1) { // n!=-1 for # of 0
    if(n==-1) return __builtin_popcountll(s);
    return n-__builtin_popcountll(s);
}
inline int parity(ll s, ll n=-1) { // n!=-1 for # of 0
    if(n==-1) return __builtin_parityll(s);
    return (n-__builtin_popcountll(s))%2;
}
inline void Out(double x) {printf("%.15f",x);cout<<'\n';}
template<typename T> inline void Out(pair<T,T> x) {cout<<x.first<<' '<<x.second<<'\n';}
template<typename T> inline void Out(T x) {cout<<x<<'\n';}
inline void Out(vector<string> v) {rep(i,SIZE(v)) cout<<v[i]<<'\n';}
template<typename T> inline void Out(queue<T> q){while(!q.empty()) {cout<<q.front()<<" "; q.pop();} cout<<endl;}
template<typename T> inline void Out(deque<T> q){while(!q.empty()) {cout<<q.front()<<" "; q.pop_front();} cout<<endl;}
template<typename T> inline void Out(vector<T> v) {rep(i,SIZE(v)) cout<<v[i]<<(i==SIZE(v)-1?'\n':' ');}
template<typename T> inline void Out(vector<vector<T>> &vv){for(auto &v: vv) Out(v);}
template<typename T> inline void Out(vector<pair<T,T>> v) {for(auto p:v) Out(p);}
template<typename T> inline void Outend(T x) {Out(x); exit(0);}
template<typename T> inline void chmin(T &a, T b) { a = min(a, b); }
template<typename T> inline void chmax(T &a, T b) { a = max(a, b); }
inline void mi(void) {return;}
template<typename T1, typename... T2> void mi(T1& f, T2&... r) {--f; mi(r...);}
template<class... T> void in(T&... x) {(cin >> ... >> x);}
template<class... T> void inm(T&... x) {(cin >> ... >> x); mi(x...);}
inline void input_ivec(vi &ivec, int n) {rep(i, n) {cin>>ivec[i];}}
inline void input_ivecm(vi &ivec, int n) {rep(i, n) {cin>>ivec[i];--ivec[i];}}
inline void input_lvec(vl &lvec, ll n) {rep(i, n) {cin>>lvec[i];}}
inline void input_lvecm(vl &lvec, ll n) {rep(i, n) {cin>>lvec[i];--lvec[i];}}
inline void input_lvec12(vl &lvec1, vl &lvec2, ll n) {rep(i, n) {cin>>lvec1[i]>>lvec2[i];}}
inline void input_lvec12m(vl &lvec1, vl &lvec2, ll n) {rep(i, n) {cin>>lvec1[i]>>lvec2[i];--lvec1[i];--lvec2[i];}}
inline void input_cvec(vc &cvec, ll n) {rep (i, n) {cin>>cvec[i];}}
inline void input_svec(vs &svec, ll n) {rep (i, n) {cin>>svec[i];}}
inline void input_dvec(vd &dvec, ll n) {rep (i, n) {cin>>dvec[i];}}
inline void input_pvec(vp &pvec, ll n) {rep (i, n) {cin>>pvec[i].first>>pvec[i].second;}}
inline void input_pvecm(vp &pvec, ll n) {rep (i, n) {cin>>pvec[i].first>>pvec[i].second;pvec[i].first--,pvec[i].second--;}}
inline void input_pvecd(vpd &pvec, ll n) {rep (i, n) {cin>>pvec[i].first>>pvec[i].second;}}
inline void input_ivec2(vvi &ivec2, int h, int w) {rep(i, h) rep(j, w) {cin>>ivec2[i][j];}}
inline void input_lvec2(vvl &lvec2, ll h, ll w) {rep(i, h) rep(j, w) {cin>>lvec2[i][j];}}
inline void input_lvec2m(vvl &lvec2, ll h, ll w) {rep(i, h) rep(j, w) {cin>>lvec2[i][j];--lvec2[i][j];}}
inline void input_cvec2(vvc &cvec2, ll h, ll w) {rep(i, h) rep(j, w) {cin>>cvec2[i][j];}}
inline bool isin(ll i, ll j, ll h, ll w) {if(i<0||i>=h||j<0||j>=w) return false; else return true;}
template<typename T> inline T TmpPercent(T a, T b) {if(b<0){a=-a,b=-b;} return (a%b+b)%b;}
template<typename T> inline T Percent(T a, T b) {if(b<0) return -TmpPercent(a,b); return TmpPercent(a,b);}
template<typename T> inline T Div(T a, T b) {if(b<0){a=-a,b=-b;} return (a-TmpPercent(a,b))/b; }
template<typename T> inline T Divceil(T a, T b) {if(TmpPercent(a,b)==0) return Div(a,b); return Div(a,b)+1;}
template<typename T> void erase(multiset<T> &st, T x) {if(st.contains(x)) st.erase(st.find(x));}
template<typename T> T pop(vector<T> &x) {T ret=x.back(); x.pop_back(); return ret;}
#ifdef __DEBUG
#define de(var) {cerr << #var << ": "; debug_view(var);}
#define de2(var1,var2) {cerr<<#var1<<' '<<#var2<<": "; debug_view(var1,var2);}
#define de3(var1,var2,var3) {cerr<<#var1<<' '<<#var2<<' '<<#var3<<": "; debug_view(var1,var2,var3);}
#define de4(var1,var2,var3,var4) {cerr<<#var1<<' '<<#var2<<' '<<#var3<<' '<<#var4<<": "; debug_view(var1,var2,var3,var4);}
#define de5(var1,var2,var3,var4,var5) {cerr<<#var1<<' '<<#var2<<' '<<#var3<<' '<<#var4<<' '<<#var5<<": "; debug_view(var1,var2,var3,var4,var5);}
template<typename T> inline void debug_view(T e){cerr << e << endl;}
template<typename T1, typename T2> inline void debug_view(T1 e1, T2 e2){cerr<<e1<<' '<<e2<<endl;}
template<typename T1, typename T2, typename T3> inline void debug_view(T1 e1, T2 e2, T3 e3){cerr<<e1<<' '<<e2<<' '<<e3<<endl;}
template<typename T1, typename T2, typename T3, typename T4> inline void debug_view(T1 e1, T2 e2, T3 e3, T4 e4){cerr<<e1<<' '<<e2<<' '<<e3<<' '<<e4<<endl;}
template<typename T1, typename T2, typename T3, typename T4, typename T5> inline void debug_view(T1 e1, T2 e2, T3 e3, T4 e4, T5 e5){cerr<<e1<<' '<<e2<<' '<<e3<<' '<<e4<<' '<<e5<<endl;}
template<typename T1, typename T2> inline void debug_view(pair<T1,T2> &p){cerr<<"{"<<p.first<<" "<<p.second<<"}\n";}
template<typename T1, typename T2> inline void debug_view(vector<pair<T1,T2>> &v){for(auto [a,b]: v){cerr<<"{"<<a<<" "<<b<<"} ";} cerr << endl;}
template<typename T1, typename T2> inline void debug_view(set<pair<T1,T2>> &s){for(auto [a,b]: s){cerr<<"{"<<a<<" "<<b<<"} ";} cerr << endl;}
template<typename T> inline void debug_view(tuple<T,T,T> t){cerr<<get<0>(t)<<' '<<get<1>(t)<<' '<<get<2>(t)<< endl;}
template<typename T> inline void debug_view(queue<T> q){while(!q.empty()) {cerr << q.front() << " "; q.pop();}cerr << endl;}
template<typename T> inline void debug_view(deque<T> q){while(!q.empty()) {cerr << q.front() << " "; q.pop_front();}cerr << endl;}
template<typename T> inline void debug_view(set<T> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(set<T,greater<T>> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(unordered_set<T> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(multiset<T> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(multiset<T,greater<T>> s){for(auto x:s){cerr << x << ' ';}cerr << endl;}
template<typename T> inline void debug_view(vector<pair<T,T>> &v){for(auto [a,b]: v){cerr<<"{"<<a<<" "<<b<<"} ";} cerr << endl;}
inline void debug_view(vector<string> &v){cerr << "----" << endl; for(auto s: v) debug_view(s);}
template<typename T> inline void debug_view(vector<T> &v){for(auto e: v){cerr << e << " ";} cerr << endl;}
template<typename T> inline void debug_view(vector<vector<pair<T,T>>> &vv){cerr << "----" << endl;for(auto &v: vv){debug_view(v);} cerr << "--------" << endl;}
template<typename T> inline void debug_view(vector<vector<T>> &vv){cerr << "----" << endl;for(auto &v: vv){debug_view(v);} cerr << "--------" << endl;}
template<typename T1,typename T2> inline void debug_view(map<T1,T2> &mp){cerr << "----" << endl;for(auto [k,v]: mp){cerr << k << ' ' << v << endl;} cerr << "--------" << endl;}
template<typename T1,typename T2> inline void debug_view(unordered_map<T1,T2> &mp){cerr << "----" << endl;for(auto [k,v]: mp){cerr << k << ' ' << v << endl;} cerr << "--------" << endl;}
template<typename T1,typename T2> inline void debug_view(map<T1,vector<T2>> &mp){cerr<<"----"<<endl;for(auto [k,v]: mp){cerr<<k<<": ";debug_view(v);} cerr << "--------" << endl;}
template<typename T1,typename T2,typename T3> inline void debug_view(map<pair<T1,T2>,T3> &mp){cerr << "----" << endl;for(auto [p,v]: mp){cerr<<'{'<<p.first<<' '<<p.second<<'}'<<": "<<v<<endl;} cerr<<"--------"<<endl;}
#define deb(var) {cerr << #var << ": "; debugb_view(var);}
template<typename T> inline void debugb_view(T e){bitset<20> b(e); cerr<<b<<endl;}
template<typename T> inline void debugb_view(vector<T> &v){cerr<<"----"<<endl;for(auto e: v){debugb_view(e);}}
#else
#define de(var) {}
#define de2(var1,var2) {}
#define de3(var1,var2,var3) {}
#define de4(var1,var2,var3,var4) {}
#define de5(var1,var2,var3,var4,var5) {}
#define deb(var) {}
#endif
int IINF = 1001001001;
ll INF = 3e18;
const ll M998 = 998244353;
const ll M107 = 1000000007;
template<typename T> inline void ch1(T &x){if(x==INF)x=-1;}
const double PI = acos(-1);
const double EPS = 1e-8;  //eg) if x=1e6, EPS >= 1e6/1e14(=1e-8)
const vi di = {0, 1, 0, -1};
const vi dj = {1, 0, -1, 0};
const vp dij = {{0,1},{1,0},{0,-1},{-1,0}};
const vp hex0 = {{-1,-1},{-1,0},{0,-1},{0,1},{1,-1},{1,0}}; // tobide
const vp hex1 = {{-1,0},{-1,1},{0,-1},{0,1},{1,0},{1,1}};  // hekomi
const vi di8 = {-1, -1, -1, 0, 0, 1, 1, 1};
const vi dj8 = {-1, 0, 1, -1, 1, -1, 0, 1};
const vp dij8 = {{0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
Pr operator+ (Pr a, Pr b) {return {a.first+b.first, a.second+b.second};}
Pr operator- (Pr a, Pr b) {return {a.first-b.first, a.second-b.second};}
Pr operator* (Pr a, Pr b) {return {a.first*b.first, a.second*b.second};}
Pr operator/ (Pr a, Pr b) {return {a.first/b.first, a.second/b.second};}

template<class T,T(*op)(T,T),T(*e)(),class F,T(*mapping)(F f,T x),F(*composition)(F f,F g),F(*id)()>
class ImplicitTreap{
    struct Node{
        T val,acc=e();
        int priority;
        int cnt=1;
        F lazy=id();
        bool rev=false;
        Node *l, *r;
        Node(T val,int priority):val(val),priority(priority),l(nullptr),r(nullptr){};
    }
    *root=nullptr;
    using Tree=Node *;

    int cnt(Tree t) { return t ? t->cnt : 0; }
    T acc(Tree t){ return t ? t->acc : e(); }
    void update(Tree t){
        if(t){
            t->cnt=1+cnt(t->l)+cnt(t->r);
            t->acc=op(t->val,op(acc(t->l),acc(t->r)));
        }
    }
    void pushdown(Tree t){
        if(t && t->rev){
            t->rev=false;
            std::swap(t->l,t->r);
            if(t->l)t->l->rev^=1;
            if(t->r)t->r->rev^=1;
        }
        if(t && t->lazy!=id()){
            if(t->l){
                t->l->lazy=composition(t->l->lazy,t->lazy);
                t->l->acc=mapping(t->lazy,t->l->acc);
            }
            if(t->r){
                t->r->lazy=composition(t->r->lazy,t->lazy);
                t->r->acc=mapping(t->lazy,t->r->acc);
            }
            t->val=mapping(t->lazy,t->val);
            t->lazy=id();
        }
        update(t);
    }
    void split(Tree t, int key, Tree& l,Tree& r){
        if(!t){
            l=r=nullptr;
            return;
        }
        pushdown(t);
        int implicit_key=cnt(t->l)+1;
        if(key<implicit_key){
            split(t->l,key,l,t->l),r=t;
        }else{
            split(t->r,key-implicit_key,t->r,r),l=t;
        }
        update(t);
    }
    void insert(Tree& t,int key,Tree item){
        Tree t1,t2;
        split(t,key,t1,t2);
        merge(t1,t1,item);
        merge(t,t1,t2);
    }
    void merge(Tree& t, Tree l, Tree r){
        pushdown(l);
        pushdown(r);
        if(!l || !r){
            t=l?l:r;
        }else if(l->priority>r->priority){
            merge(l->r,l->r,r),t=l;
        }else{
            merge(r->l,l,r->l),t=r;
        }
        update(t);
    }
    void erase(Tree& t,int key){
        Tree t1,t2,t3;
        split(t,key+1,t1,t2);
        split(t1,key,t1,t3);
        merge(t,t1,t2);
    }
    T prod(Tree t,int l,int r){
        Tree t1,t2,t3;
        split(t,l,t1,t2);
        split(t2,r-l,t2,t3);
        T ret=t2->acc;
        merge(t2,t2,t3);
        merge(t,t1,t2);
        return ret;
    }
    void apply(Tree t,int l,int r,F x){
        Tree t1,t2,t3;
        split(t,l,t1,t2);
        split(t2,r-l,t2,t3);
        t2->lazy=composition(t2->lazy,x);
        t2->acc=mapping(x,t2->acc);
        merge(t2,t2,t3);
        merge(t,t1,t2);
    }
    void reverse(Tree t,int l,int r){
        if(l>r)return;
        Tree t1,t2,t3;
        split(t,l,t1,t2);
        split(t2,r-l,t2,t3);
        t2->rev^=1;
        merge(t2,t2,t3);
        merge(t,t1,t2);
    }
    void rotate(Tree t,int l,int m,int r){
        reverse(t,l,r);
        reverse(t,l,l+r-m);
        reverse(t,l+r-m,r);
    }
    void dump(Tree t) {
        if (!t) return;
        pushdown(t);
        dump(t->l);
        std::cerr << t->val << " ";
        dump(t->r);
    }
public:
    ImplicitTreap() {}
    ImplicitTreap(std::vector<T> as){
        std::reverse(as.begin(),as.end());
        for(T a:as){ insert(0,a); }
    }
    void insert(int pos,T val){
        //valをposの場所に追加する O(log N)
        insert(root,pos,new Node(val,rand()));
    }
    void erase(T pos){
        //posにある要素を消す O(log N)
        erase(root,pos);
    }
    int size(){ return cnt(root); }
    T operator[](int pos) {
        Tree t1, t2, t3;
        split(root, pos + 1, t1, t2);
        split(t1, pos, t1, t3);
        T ret = t3->acc;
        merge(t1, t1, t3);
        merge(root, t1, t2);
        return ret;
    }
    T prod(int l, int r){
        //[l,r)の区間 O(log N)
        return prod(root,l,r);
    }
    void apply(int l,int r,F x){ apply(root,l,r,x); }
    void reverse(int l,int r){ reverse(root,l,r); }
    void rotate(int l,int m,int r){ rotate(root,l,m,r); }
    void dump(){ 
        #ifdef __DEBUG
        dump(root);std::cerr<<std::endl;
        #endif
    }
};

ll op(ll a, ll b) {return min(a,b);}
ll e() {return INF;}

void solve() {
    LONG(N, Q);
    VL(A, N);
    ImplicitTreap<ll,op,e,ll,op,op,e> tree(A);
    rep(i, Q) {
        LONG(t);
        if(t==0) {
            LONG(l, r);
            tree.rotate(l,r,r+1);
        } else if(t==1) {
            LONG(l, r);
            ll ans = tree.prod(l,r+1);
            Out(ans);
        } else {
            LONG(p,x);
            tree.erase(p);
            tree.insert(p,x);
        }
        // tree.dump();
    }

}

int main () {
    // ios::sync_with_stdio(false);
    cin.tie(nullptr);
    solve();
}

// ### test.cpp ###
accuracy: 1
time_ms: 570
memory_kb: 21252
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

#ifdef LOCAL
#include <debug.hpp>
#else
#define debug(...)
#endif

template <class S, S (*op)(S, S), S (*e)()>
class SplayTree {
   private:
    struct Node {
        S val, sum;             // 自身の値と部分木全体の集約値
        int size;               // 部分木のサイズ
        bool rev;               // 遅延反転フラグ
        Node *lch, *rch, *par;  // 左子、右子、親へのポインタ

        Node() : val(e()), sum(e()), size(0), rev(false), lch(nullptr), rch(nullptr), par(nullptr) {}
        Node(const S& v) : val(v), sum(v), size(1), rev(false), lch(nullptr), rch(nullptr), par(nullptr) {}
    };

    Node* root;

    inline int size(Node* t) const { return t ? t->size : 0; }
    inline S sum(Node* t) const { return t ? t->sum : e(); }

    // t のサイズ・集約値を左右の子から更新
    inline void push_up(Node* t) {
        if (!t) return;
        t->size = 1;
        t->sum = t->val;
        if (t->lch) {
            t->size += t->lch->size;
            t->sum = op(t->lch->sum, t->sum);
        }
        if (t->rch) {
            t->size += t->rch->size;
            t->sum = op(t->sum, t->rch->sum);
        }
    }

    // 反転フラグが立っていたら子に伝搬し、左右の子を入れ替える
    inline void push_down(Node* t) {
        if (t && t->rev) {
            swap(t->lch, t->rch);
            if (t->lch) t->lch->rev ^= true;
            if (t->rch) t->rch->rev ^= true;
            t->rev = false;
        }
    }

    // x とその親 p を回転する（x を上げる）
    void rotate(Node* x) {
        Node *p = x->par, *g = p->par;
        push_down(p);
        push_down(x);
        if (x == p->lch) {
            p->lch = x->rch;
            if (x->rch) x->rch->par = p;
            x->rch = p;
        } else {
            p->rch = x->lch;
            if (x->lch) x->lch->par = p;
            x->lch = p;
        }
        x->par = g;
        if (g) {
            if (p == g->lch)
                g->lch = x;
            else
                g->rch = x;
        }
        p->par = x;
        push_up(p);
        push_up(x);
    }

    // k 番目 (0 <= t < size) のノードを根に持ってくる
    Node* kth_element(Node* t, int k) {
        while (true) {
            push_down(t);
            int lsize = size(t->lch);
            if (k == lsize) break;
            if (k < lsize) {
                t = t->lch;
            } else if (k > lsize) {
                k -= lsize + 1;
                t = t->rch;
            }
        }
        splay(t);
        return t;
    }

    // x を根に持ってくる
    void splay(Node* x) {
        if (!x) return;
        while (x->par) {
            Node* p = x->par;
            Node* g = p->par;
            if (g) push_down(g);
            push_down(p);
            push_down(x);
            if (!g) {
                rotate(x);
            } else if ((g->lch == p && p->lch == x) || (g->rch == p && p->rch == x)) {
                rotate(p);
                rotate(x);
            } else {
                rotate(x);
                rotate(x);
            }
        }
        root = x;
    }

    // 木 t を先頭 k 個と残りに分割し、ペア {l, t} を返す
    pair<Node*, Node*> split(Node* t, int k) {
        if (!t) return {nullptr, nullptr};
        if (k == 0) return {nullptr, t};
        if (k >= size(t)) return {t, nullptr};
        // t を k 番目のノードが根になるよう splay する
        t = kth_element(t, k);
        Node* l = t->lch;
        l->par = nullptr;
        t->lch = nullptr;
        push_up(t);
        return {l, t};
    }

    // l, r を結合する
    Node* merge(Node* l, Node* r) {
        if (!l) return r;
        if (!r) return l;
        // l の最大要素（右端）を splay する
        l = kth_element(l, size(l) - 1);
        l->rch = r;
        r->par = l;
        push_up(l);
        return l;
    }

    Node* build(const vector<S>& V, int l, int r) {
        if (l >= r) return nullptr;
        int m = (l + r) >> 1;
        Node* t = new Node(V[m]);
        t->lch = build(V, l, m);
        t->rch = build(V, m + 1, r);
        if (t->lch) t->lch->par = t;
        if (t->rch) t->rch->par = t;
        push_up(t);
        return t;
    }

    void delete_all(Node* t) {
        if (!t) return;
        delete_all(t->lch);
        delete_all(t->rch);
        delete t;
    }

   public:
    SplayTree() : root(nullptr) {}
    SplayTree(const vector<S>& V) : root(nullptr) {
        if (!V.empty()) root = build(V, 0, V.size());
    }
    ~SplayTree() { delete_all(root); }

    // get: k (0 <= k < size) 番目の要素の値を返す
    S get(int k) {
        assert(root && 0 <= k && k < root->size);
        return kth_element(root, k)->val;
    }

    // insert: 位置 k に値 v を挿入する
    void insert(int k, S v) {
        assert(0 <= k && k <= size(root));
        Node* newNode = new Node(v);
        if (!root) {
            root = newNode;
            return;
        }
        if (k == 0) {
            root = merge(newNode, root);
        } else if (k == size(root)) {
            root = merge(root, newNode);
        } else {
            auto [L, R] = split(root, k);
            root = merge(merge(L, newNode), R);
        }
    }

    // erase: 位置 k の要素を削除する
    void erase(int k) {
        assert(root && 0 <= k && k < root->size);
        Node* target = kth_element(root, k);
        Node *L = target->lch, *R = target->rch;
        if (L) L->par = nullptr;
        if (R) R->par = nullptr;
        delete target;
        root = merge(L, R);
    }

    // update: 位置 k の値を v に更新する
    void update(int k, S v) {
        assert(root && 0 <= k && k < root->size);
        Node* target = kth_element(root, k);
        target->val = v;
        push_up(target);
    }

    // prod: 区間 [l, r) の要素を op で集約した値を返す
    S prod(int l, int r) {
        assert(0 <= l && r <= size());
        if (l >= r) return e();
        auto [A, BC] = split(root, l);
        auto [B, C] = split(BC, r - l);
        S res = B ? B->sum : e();
        root = merge(A, merge(B, C));
        return res;
    }

    // reverse: 区間 [l, r) の要素を反転する
    void reverse(int l, int r) {
        assert(0 <= l && r <= size());
        if (l >= r) return;
        auto [A, BC] = split(root, l);
        auto [B, C] = split(BC, r - l);
        if (B) B->rev ^= true;
        root = merge(A, merge(B, C));
    }

    // rotate: 区間 [l, r) を m 番目の要素が先頭になるように巡回シフトする
    // 0 <= l < m < r <= size()
    void rotate(int l, int m, int r) {
        assert(0 <= l && l < m && m < r && r <= size());
        auto [A, BC] = split(root, l);
        auto [B, C] = split(BC, r - l);
        auto [B1, B2] = split(B, m - l);  // B = [B1, B2] で、B2 が先頭に来る
        B = merge(B2, B1);
        root = merge(A, merge(B, C));
    }

    bool empty() const { return root == nullptr; }
    int size() const { return size(root); }
    S operator[](int k) { return get(k); }
};

using S = int;
S op(S a, S b) { return min(a, b); }
S e() { return 1e9; }

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(20);
    int N, Q;
    cin >> N >> Q;
    vector<int> A(N);
    for (int i = 0; i < N; i++) cin >> A[i];

    SplayTree<S, op, e> sp(A);
    while (Q--) {
        int x, y, z;
        cin >> x >> y >> z;
        if (x == 0) {
            // [l, r] を r が先頭になるように巡回シフト
            sp.rotate(y, z, z + 1);
        }
        if (x == 1) {
            cout << sp.prod(y, z + 1) << '\n';
        }
        if (x == 2) {
            sp.update(y, z);
        }
    }
}
accuracy: 1
time_ms: 280
memory_kb: 13568
final_rank: 6

code_snippet: #line 2 "template.hpp"
// #pragma GCC target("avx2")
// #pragma GCC optimize("O3")
// #pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>
using namespace std;
// https://xn--kst.jp/blog/2019/08/29/cpp-comp/
// debug methods
// usage: debug(x,y);
// vector 出力できるように修正
template <typename T>
ostream& debug_print(ostream& os, const vector<T>& v) {
    os << "[";
    for (size_t i = 0; i < v.size(); ++i) {
        os << v[i];
        if (i < v.size() - 1) os << ", ";
    }
    os << "]";
    return os;
}
template <typename T>
ostream& debug_print(ostream& os, const T& var) {
    os << var;
    return os;
}
#define CHOOSE(a) CHOOSE2 a
#define CHOOSE2(a0, a1, a2, a3, a4, x, ...) x
#define debug_1(x1) { cout << #x1 << ": "; debug_print(cout, x1) << endl; }
#define debug_2(x1, x2) { cout << #x1 << ": "; debug_print(cout, x1) << ", " << #x2 << ": "; debug_print(cout, x2) << endl; }
#define debug_3(x1, x2, x3) { cout << #x1 << ": "; debug_print(cout, x1) << ", " << #x2 << ": "; debug_print(cout, x2) << ", " << #x3 << ": "; debug_print(cout, x3) << endl; }
#define debug_4(x1, x2, x3, x4) { cout << #x1 << ": "; debug_print(cout, x1) << ", " << #x2 << ": "; debug_print(cout, x2) << ", " << #x3 << ": "; debug_print(cout, x3) << ", " << #x4 << ": "; debug_print(cout, x4) << endl; }
#define debug_5(x1, x2, x3, x4, x5) { cout << #x1 << ": "; debug_print(cout, x1) << ", " << #x2 << ": "; debug_print(cout, x2) << ", " << #x3 << ": "; debug_print(cout, x3) << ", " << #x4 << ": "; debug_print(cout, x4) << ", " << #x5 << ": "; debug_print(cout, x5) << endl; }

#ifdef LOCAL
#define debug(...) CHOOSE((__VA_ARGS__, debug_5, debug_4, debug_3, debug_2, debug_1, ~))(__VA_ARGS__)
#else
#define debug(...)
#endif

using ll = long long;
using vl = vector<ll>;
using Graph = vector<vector<ll>>;
using P = pair<ll, ll>;
#define all(v) v.begin(), v.end()
template <typename T> inline bool chmax(T &a, T b) {
    return ((a < b) ? (a = b, true) : (false));
}
template <typename T> inline bool chmin(T &a, T b) {
    return ((a > b) ? (a = b, true) : (false));
}
#define rep1(i, n) for(ll i = 1; i <= ((ll)n); ++i)
// https://trap.jp/post/1224/
template <class... T> constexpr auto min(T... a) {
    return min(initializer_list<common_type_t<T...>>{a...});
}
template <class... T> constexpr auto max(T... a) {
    return max(initializer_list<common_type_t<T...>>{a...});
}
template <class... T> void input(T &...a) { (cin >> ... >> a); }
template <class T> void input(vector<T> &a) {
    for(T &x : a)
        cin >> x;
}
void print() { cout << '\n'; }
template <class T, class... Ts> void print(const T &a, const Ts &...b) {
    cout << a;
    (cout << ... << (cout << ' ', b));
    cout << '\n';
}
void print(const string &s) {
    cout << s << '\n';
}
template <class Container, typename = void>
struct is_container : std::false_type {};
template <class Container>
struct is_container<Container, std::void_t<decltype(std::declval<Container>().begin()), decltype(std::declval<Container>().end())>> : std::true_type {};
template <class Container>
typename enable_if<is_container<Container>::value>::type print(const Container& x) {
    if (!x.empty()) {
        auto it = x.begin();
        for (; it != prev(x.end()); ++it) {
            cout << *it << " ";
        }
        cout << *it << "\n";  // 最後の要素を出力して改行
    }
}
#define INT(...)                                                               \
    int __VA_ARGS__;                                                           \
    input(__VA_ARGS__)
#define LL(...)                                                                \
    long long __VA_ARGS__;                                                     \
    input(__VA_ARGS__)
#define STR(...)                                                               \
    string __VA_ARGS__;                                                        \
    input(__VA_ARGS__)
#define REP1(a) for(ll i = 0; i < a; i++)
#define REP2(i, a) for(ll i = 0; i < a; i++)
#define REP3(i, a, b) for(ll i = a; i < b; i++)
#define REP4(i, a, b, c) for(ll i = a; i < b; i += c)
#define overload4(a, b, c, d, e, ...) e
#define rep(...) overload4(__VA_ARGS__, REP4, REP3, REP2, REP1)(__VA_ARGS__)

ll inf = 3e18;
vl dx = {1, -1, 0, 0};
vl dy = {0, 0, 1, -1};
#line 2 "/home/y_midori/cp/test.cpp"
// #include "data_structure/hash-map-variable-length.hpp"
// #include "math/pollard_rho.hpp"
// #include <atcoder/modint>
// using mint = atcoder::modint998244353;

// std::random_device rd;  // ハードウェア乱数生成器
// std::mt19937 gen(rd()); // メルセンヌ・ツイスタの32ビット版
// // 分布を指定
// std::uniform_int_distribution<ll> dist(1, 1LL << 60);
struct SplayNode {
    SplayNode *left, *right, *parent;
    int size, value, minumum;

    SplayNode() {
        left = nullptr;
        right = nullptr;
        parent = nullptr;
        size = 1;
    }

    void rotate() {
        SplayNode *pp, *p, *c;
        p = this->parent;
        pp = p->parent;
        // 変更するのは3辺,6つ
        if(p->left == this) {
            c = this->right;
            this->right = p;
            p->left = c;
        } else {
            c = this->left;
            this->left = p;
            p->right = c;
        }
        if(pp) {
            if(pp->right == p) {
                pp->right = this;
            } else {
                pp->left = this;
            }
        }
        this->parent = pp;
        p->parent = this;
        if(c)
            c->parent = p;
        // p,thisのsizeを下から更新
        p->update();
        this->update();
    }
    int state() {
        if(!this->parent)
            return 0;
        if(this->parent->left == this)
            return 1;
        if(this->parent->right == this)
            return 2;
        return 0;
    }
    void splay() {
        while(this->parent) {
            if(this->parent->state() == 0) {
                this->rotate();
            } else if(this->state() == this->parent->state()) {
                this->parent->rotate();
                this->rotate();
            } else {
                this->rotate();
                this->rotate();
            }
        }
    }
    void update() {
        this->size = 1;
        this->minumum = this->value;
        if(this->left) {
            this->size += this->left->size;
            chmin(this->minumum, this->left->minumum);
        }
        if(this->right) {
            this->size += this->right->size;
            chmin(this->minumum, this->right->minumum);
        }
    }
};
SplayNode *get(int idx, SplayNode *root) {
    SplayNode *now = root;
    while(true) {
        int l_size = now->left ? now->left->size : 0;
        if(idx < l_size) {
            now = now->left;
        } else if(idx == l_size) {
            now->splay();
            return now;
        } else {
            idx -= l_size + 1;
            now = now->right;
        }
    }
}
typedef SplayNode SN;
SN *merge(SN *l_root, SN *r_root) {
    if(!l_root)
        return r_root;
    if(!r_root)
        return l_root;
    l_root = get(l_root->size - 1, l_root);
    l_root->right = r_root;
    r_root->parent = l_root;
    l_root->update();
    return l_root;
}
pair<SN *, SN *> split(int l_size, SN *root) {
    if(l_size == 0)
        return {nullptr, root};
    if(l_size == root->size)
        return {root, nullptr};
    root = get(l_size, root);
    SN *l_root, *r_root;
    l_root = root->left;
    r_root = root;
    r_root->left = nullptr;
    l_root->parent = nullptr;
    r_root->update();
    return {l_root, r_root};
}
SN *insert(int idx, SN *node, SN *root) {
    // {0,1,2} --(idx=1,val=3)--> {0,3,1,2}
    SN *l_root, *r_root;
    tie(l_root, r_root) = split(idx, root);
    return merge(merge(l_root, node), r_root);
}
pair<SN *, SN *> remove(int idx, SN *root) {
    // deleteは予約後
    // {残った木の根,消したnode}
    // {0,1,2} --(idx=1)--> {0,2}
    root = get(idx, root);
    SN *l_root = root->left, *r_root = root->right;
    if(l_root)
        l_root->parent = nullptr;
    if(r_root)
        r_root->parent = nullptr;
    root->left = nullptr;
    root->right = nullptr;
    root->update();
    return {merge(l_root, r_root), root};
}
SN *shift(ll l, ll r, SN *root) {
    // shift {a_l, ... ,a_{r-1}}
    SN *node;
    tie(root, node) = remove(r - 1, root);
    return insert(l, node, root);
}
pair<SN *, int> prod(ll l, ll r, SN *root) {
    // prod {a_l, ... , a_{r-1}}
    SN *l_root, *c_root, *r_root;
    tie(root, r_root) = split(r, root);
    tie(l_root, c_root) = split(l, root);
    int res = c_root->minumum;
    return {merge(merge(l_root, c_root), r_root), res};
}
SplayNode node[210000];
void solve() {
    LL(n, q);
    rep(i, n) {
        LL(ai);
        node[i].value = ai;
        if(i) {
            node[i].left = &node[i - 1];
            node[i - 1].parent = &node[i];
        }
        node[i].update();
    }
    SN *root = &node[n - 1];
    while(q--) {
        LL(x);
        if(x == 0) {
            LL(l, r);
            r++;
            root = shift(l, r, root);
        } else if(x == 1) {
            LL(l, r);
            r++;
            int ans;
            tie(root, ans) = prod(l, r, root);
            print(ans);
        } else {
            LL(idx, val);
            root = get(idx, root);
            root->value = val;
            root->update();
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    cout << std::setprecision(16);
    int t = 1;
    rep(_, t) {
        solve();
    }
}
accuracy: 1
time_ms: 310
memory_kb: 11640
final_rank: 2

code_snippet: // competitive-verifier: PROBLEM https://onlinejudge.u-aizu.ac.jp/problems/1508
#include <iostream>
#include <algorithm>
#include <cassert>
#include <random>
#include <tuple>
#include <utility>
/// @brief 動的配列
template <class M, class UniformRandomBitGenerator = std::mt19937>
struct dynamic_sequence {
  private:
    using T = typename M::value_type;
    using priority_type = typename UniformRandomBitGenerator::result_type;
    struct node_t {
        using pointer = node_t *;
        static int count(pointer t) { return !t ? 0 : t->cnt; }
        static T composition(pointer t) { return !t ? M::id() : t->acc; }
        node_t(const T &v, priority_type p)
            : val(v), acc(v), ch{nullptr, nullptr}, priority(p), cnt(1), rev() {}
        node_t(T &&v, priority_type p)
            : val(v), acc(v), ch{nullptr, nullptr}, priority(p), cnt(1), rev() {}
        T val, acc;
        pointer ch[2];
        priority_type priority;
        int cnt;
        bool rev;
    };
    using node_ptr = typename node_t::pointer;
  public:
    dynamic_sequence() : root(nullptr) {}
    dynamic_sequence(node_ptr p) : root(p) {}
    int size() const { return node_t::count(root); }
    T get(int k) const {
        assert(k < node_t::count(root));
        node_ptr node = root;
        while (true) {
            push(node);
            int c = node_t::count(node->ch[0]);
            if (c == k) break;
            if (k < c) node = node->ch[0];
            else node = node->ch[1], k -= c + 1;
        }
        return node->val;
    }
    void set(int k, T val) {
        assert(k < node_t::count(root));
        node_ptr node = root;
        std::vector<node_ptr> nodes;
        while (true) {
            push(node);
            nodes.emplace_back(node);
            int c = node_t::count(node->ch[0]);
            if (c == k) break;
            if (k < c) node = node->ch[0];
            else node = node->ch[1], k -= c + 1;
        }
        node->val = val;
        std::reverse(nodes.begin(), nodes.end());
        for (auto t : nodes) update(t);
    }
    void insert(int k, T val) { root = insert(root, k, val); }
    void push_front(const T &val) {
        node_ptr node = new node_t(val, gen());
        root = merge(node, root);
    }
    void push_front(T &&val) {
        node_ptr node = new node_t(std::move(val), gen());
        root = merge(node, root);
    }
    void push_back(const T &val) {
        node_ptr node = new node_t(val, gen());
        root = merge(root, node);
    }
    void push_back(T &&val) {
        node_ptr node = new node_t(std::move(val), gen());
        root = merge(root, node);
    }
    void erase(int k) { root = erase(root, k); }
    T prod(int r) const { return prod(root, r); }
    T prod(int l, int r) {
        assert(0 <= l && l <= r && r <= node_t::count(root));
        std::pair<node_ptr, node_ptr> p = split(root, l);
        T res = prod(p.second, r - l);
        root = merge(p.first, p.second);
        return res;
    }
    void reverse(int l, int r) {
        std::pair<node_ptr, node_ptr> sr = split(root, r);
        std::pair<node_ptr, node_ptr> sl = split(sr.first, l);
        if (sl.second) sl.second->rev ^= true;
        root = merge(sl.first, sl.second);
        root = merge(root, sr.second);
    }
    int lower_bound(T key) {
        node_ptr node = root;
        int res = 0;
        while (node) {
            int c = node_t::count(node->ch[0]);
            if (node->acc < key) node = node->ch[1], res += c + 1;
            else node = node->ch[0];
        }
        return res;
    }
    std::pair<dynamic_sequence, dynamic_sequence> split(int k) {
        auto [pl, pr] = split(root, k);
        return std::make_pair(dynamic_sequence(pl), dynamic_sequence(pr));
    }
    std::tuple<dynamic_sequence, dynamic_sequence, dynamic_sequence> split(int l, int r) {
        auto [pl, pr] = split(root, r);
        auto [ql, qr] = split(pl, l);
        return std::make_tuple(dynamic_sequence(ql), dynamic_sequence(qr), dynamic_sequence(pr));
    }
    void merge_left(dynamic_sequence lhs) { root = merge(lhs.root, root); }
    void merge_right(dynamic_sequence rhs) { root = merge(root, rhs.root); }
  private:
    static inline UniformRandomBitGenerator gen = UniformRandomBitGenerator();
    node_ptr root;
    void push(node_ptr t) {
        if (t && t->rev) {
            std::swap(t->ch[0], t->ch[1]);
            if (t->ch[0]) t->ch[0]->rev ^= true;
            if (t->ch[1]) t->ch[1]->rev ^= true;
            t->rev = false;
        }
    }
    node_ptr update(node_ptr t) {
        push(t);
        t->cnt = node_t::count(t->ch[0]) + node_t::count(t->ch[1]) + 1;
        t->acc = M::op(M::op(node_t::composition(t->ch[0]), t->val), node_t::composition(t->ch[1]));
        return t;
    }
    node_ptr merge(node_ptr l, node_ptr r) {
        if (!l || !r) return !l ? r : l;
        push(l);
        push(r);
        if (l->priority > r->priority) {
            l->ch[1] = merge(l->ch[1], r);
            return update(l);
        } else {
            r->ch[0] = merge(l, r->ch[0]);
            return update(r);
        }
    }
    std::pair<node_ptr, node_ptr> split(node_ptr t, int k) {
        if (!t) return std::make_pair<node_ptr, node_ptr>(nullptr, nullptr);
        push(t);
        if (k <= node_t::count(t->ch[0])) {
            auto s = split(t->ch[0], k);
            t->ch[0] = s.second;
            return std::make_pair(s.first, update(t));
        } else {
            auto s = split(t->ch[1], k - node_t::count(t->ch[0]) - 1);
            t->ch[1] = s.first;
            return std::make_pair(update(t), s.second);
        }
    }
    node_ptr insert(node_ptr t, int k, T v) {
        std::pair<node_ptr, node_ptr> s = split(t, k);
        node_ptr res = new node_t(v, gen());
        res = merge(s.first, res);
        res = merge(res, s.second);
        return res;
    }
    node_ptr erase(node_ptr t, int k) {
        int c = node_t::count(t->ch[0]);
        if (k == c) return merge(t->ch[0], t->ch[1]);
        if (k < c) {
            t->ch[0] = erase(t->ch[0], k);
            return update(t);
        } else {
            t->ch[1] = erase(t->ch[1], k - c - 1);
            return update(t);
        }
    }
    T prod(node_ptr t, int r) const {
        assert(0 <= r && r <= node_t::count(t));
        T res = M::id();
        while (r) {
            if (r == node_t::count(t)) {
                res = M::op(res, node_t::composition(t));
                break;
            }
            int c = node_t::count(t->ch[0]);
            if (r < c) {
                t = t->ch[0];
                continue;
            }
            res = M::op(res, node_t::composition(t->ch[0]));
            r -= c;
            if (r) res = M::op(res, t->val), --r;
            t = t->ch[1];
        }
        return res;
    }
};
#include <limits>
#include <numeric>
template <class T>
struct Add {
    using value_type = T;
    static constexpr T id() { return T(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs + rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs + rhs;
    }
};
template <class T>
struct Mul {
    using value_type = T;
    static constexpr T id() { return T(1); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs * rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs * rhs;
    }
};
template <class T>
struct And {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs & rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs & rhs;
    }
};
template <class T>
struct Or {
    using value_type = T;
    static constexpr T id() { return T(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs | rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs | rhs;
    }
};
template <class T>
struct Xor {
    using value_type = T;
    static constexpr T id() { return T(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs ^ rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs ^ rhs;
    }
};
template <class T>
struct Min {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) { return std::min(lhs, rhs); }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return std::min((U)lhs, rhs);
    }
};
template <class T>
struct Max {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::lowest(); }
    static constexpr T op(const T &lhs, const T &rhs) { return std::max(lhs, rhs); }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return std::max((U)lhs, rhs);
    }
};
template <class T>
struct Gcd {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) {
        return lhs == Gcd::id() ? rhs : (rhs == Gcd::id() ? lhs : std::gcd(lhs, rhs));
    }
};
template <class T>
struct Lcm {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) {
        return lhs == Lcm::id() ? rhs : (rhs == Lcm::id() ? lhs : std::lcm(lhs, rhs));
    }
};
template <class T>
struct Update {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs == Update::id() ? rhs : lhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs == Update::id() ? rhs : lhs;
    }
};
template <class T>
struct Affine {
    using P = std::pair<T, T>;
    using value_type = P;
    static constexpr P id() { return P(1, 0); }
    static constexpr P op(P lhs, P rhs) {
        return {lhs.first * rhs.first, lhs.first * rhs.second + lhs.second};
    }
};
template <class M>
struct Rev {
    using T = typename M::value_type;
    using value_type = T;
    static constexpr T id() { return M::id(); }
    static constexpr T op(T lhs, T rhs) { return M::op(rhs, lhs); }
};
int main(void) {
    int n, q;
    std::cin >> n >> q;
    dynamic_sequence<Min<int>> ds;
    for (int i = 0; i < n; ++i) {
        int x;
        std::cin >> x;
        ds.push_back(x);
    }
    while (q--) {
        int t;
        std::cin >> t;
        if (t == 0) {
            int l, r;
            std::cin >> l >> r, ++r;
            if (l + 1 == r)
                continue;
            auto [lp, mp, rp] = ds.split(l, r);
            auto [lm, rm] = mp.split(r - l - 1);
            rm.merge_right(lm);
            lp.merge_right(rm);
            lp.merge_right(rp);
            ds = lp;
        } else if (t == 1) {
            int l, r;
            std::cin >> l >> r, ++r;
            std::cout << ds.prod(l, r) << '\n';
        } else {
            int k, x;
            std::cin >> k >> x;
            ds.set(k, x);
        }
    }
    return 0;
}
accuracy: 1
time_ms: 340
memory_kb: 12824
final_rank: 5

code_snippet: // competitive-verifier: PROBLEM https://onlinejudge.u-aizu.ac.jp/problems/1508
#include <iostream>
#include <algorithm>
#include <cassert>
#include <random>
#include <tuple>
#include <utility>
/// @brief 動的配列
template <class M, class UniformRandomBitGenerator = std::mt19937>
struct dynamic_sequence {
  private:
    using T = typename M::value_type;
    using priority_type = typename UniformRandomBitGenerator::result_type;
    struct node_t {
        using pointer = node_t *;
        static int count(pointer t) { return !t ? 0 : t->cnt; }
        static T composition(pointer t) { return !t ? M::id() : t->acc; }
        node_t(const T &v, priority_type p)
            : val(v), acc(v), ch{nullptr, nullptr}, priority(p), cnt(1), rev() {}
        node_t(T &&v, priority_type p)
            : val(v), acc(v), ch{nullptr, nullptr}, priority(p), cnt(1), rev() {}
        T val, acc;
        pointer ch[2];
        priority_type priority;
        int cnt;
        bool rev;
    };
    using node_ptr = typename node_t::pointer;
  public:
    dynamic_sequence() : root(nullptr) {}
    dynamic_sequence(node_ptr p) : root(p) {}
    int size() const { return node_t::count(root); }
    T get(int k) const {
        assert(k < node_t::count(root));
        node_ptr node = root;
        while (true) {
            push(node);
            int c = node_t::count(node->ch[0]);
            if (c == k) break;
            if (k < c) node = node->ch[0];
            else node = node->ch[1], k -= c + 1;
        }
        return node->val;
    }
    void set(int k, T val) {
        assert(k < node_t::count(root));
        node_ptr node = root;
        std::vector<node_ptr> nodes;
        while (true) {
            push(node);
            nodes.emplace_back(node);
            int c = node_t::count(node->ch[0]);
            if (c == k) break;
            if (k < c) node = node->ch[0];
            else node = node->ch[1], k -= c + 1;
        }
        node->val = val;
        std::reverse(nodes.begin(), nodes.end());
        for (auto t : nodes) update(t);
    }
    void insert(int k, T val) { root = insert(root, k, val); }
    void push_front(const T &val) {
        node_ptr node = new node_t(val, gen());
        root = merge(node, root);
    }
    void push_front(T &&val) {
        node_ptr node = new node_t(std::move(val), gen());
        root = merge(node, root);
    }
    void push_back(const T &val) {
        node_ptr node = new node_t(val, gen());
        root = merge(root, node);
    }
    void push_back(T &&val) {
        node_ptr node = new node_t(std::move(val), gen());
        root = merge(root, node);
    }
    void erase(int k) { root = erase(root, k); }
    T prod(int r) const { return prod(root, r); }
    T prod(int l, int r) {
        assert(0 <= l && l <= r && r <= node_t::count(root));
        std::pair<node_ptr, node_ptr> p = split(root, l);
        T res = prod(p.second, r - l);
        root = merge(p.first, p.second);
        return res;
    }
    void reverse(int l, int r) {
        std::pair<node_ptr, node_ptr> sr = split(root, r);
        std::pair<node_ptr, node_ptr> sl = split(sr.first, l);
        if (sl.second) sl.second->rev ^= true;
        root = merge(sl.first, sl.second);
        root = merge(root, sr.second);
    }
    int lower_bound(T key) {
        node_ptr node = root;
        int res = 0;
        while (node) {
            int c = node_t::count(node->ch[0]);
            if (node->acc < key) node = node->ch[1], res += c + 1;
            else node = node->ch[0];
        }
        return res;
    }
    std::pair<dynamic_sequence, dynamic_sequence> split(int k) {
        auto [pl, pr] = split(root, k);
        return std::make_pair(dynamic_sequence(pl), dynamic_sequence(pr));
    }
    std::tuple<dynamic_sequence, dynamic_sequence, dynamic_sequence> split(int l, int r) {
        auto [pl, pr] = split(root, r);
        auto [ql, qr] = split(pl, l);
        return std::make_tuple(dynamic_sequence(ql), dynamic_sequence(qr), dynamic_sequence(pr));
    }
    void merge_left(dynamic_sequence lhs) { root = merge(lhs.root, root); }
    void merge_right(dynamic_sequence rhs) { root = merge(root, rhs.root); }
  private:
    static inline UniformRandomBitGenerator gen = UniformRandomBitGenerator();
    node_ptr root;
    void push(node_ptr t) {
        if (t && t->rev) {
            std::swap(t->ch[0], t->ch[1]);
            if (t->ch[0]) t->ch[0]->rev ^= true;
            if (t->ch[1]) t->ch[1]->rev ^= true;
            t->rev = false;
        }
    }
    node_ptr update(node_ptr t) {
        push(t);
        t->cnt = node_t::count(t->ch[0]) + node_t::count(t->ch[1]) + 1;
        t->acc = M::op(M::op(node_t::composition(t->ch[0]), t->val), node_t::composition(t->ch[1]));
        return t;
    }
    node_ptr merge(node_ptr l, node_ptr r) {
        if (!l || !r) return !l ? r : l;
        push(l);
        push(r);
        if (l->priority > r->priority) {
            l->ch[1] = merge(l->ch[1], r);
            return update(l);
        } else {
            r->ch[0] = merge(l, r->ch[0]);
            return update(r);
        }
    }
    std::pair<node_ptr, node_ptr> split(node_ptr t, int k) {
        if (!t) return std::make_pair<node_ptr, node_ptr>(nullptr, nullptr);
        push(t);
        if (k <= node_t::count(t->ch[0])) {
            auto s = split(t->ch[0], k);
            t->ch[0] = s.second;
            return std::make_pair(s.first, update(t));
        } else {
            auto s = split(t->ch[1], k - node_t::count(t->ch[0]) - 1);
            t->ch[1] = s.first;
            return std::make_pair(update(t), s.second);
        }
    }
    node_ptr insert(node_ptr t, int k, T v) {
        std::pair<node_ptr, node_ptr> s = split(t, k);
        node_ptr res = new node_t(v, gen());
        res = merge(s.first, res);
        res = merge(res, s.second);
        return res;
    }
    node_ptr erase(node_ptr t, int k) {
        int c = node_t::count(t->ch[0]);
        if (k == c) return merge(t->ch[0], t->ch[1]);
        if (k < c) {
            t->ch[0] = erase(t->ch[0], k);
            return update(t);
        } else {
            t->ch[1] = erase(t->ch[1], k - c - 1);
            return update(t);
        }
    }
    T prod(node_ptr t, int r) const {
        assert(0 <= r && r <= node_t::count(t));
        T res = M::id();
        while (r) {
            if (r == node_t::count(t)) {
                res = M::op(res, node_t::composition(t));
                break;
            }
            int c = node_t::count(t->ch[0]);
            if (r < c) {
                t = t->ch[0];
                continue;
            }
            res = M::op(res, node_t::composition(t->ch[0]));
            r -= c;
            if (r) res = M::op(res, t->val), --r;
            t = t->ch[1];
        }
        return res;
    }
};
#include <limits>
#include <numeric>
template <class T>
struct Add {
    using value_type = T;
    static constexpr T id() { return T(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs + rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs + rhs;
    }
};
template <class T>
struct Mul {
    using value_type = T;
    static constexpr T id() { return T(1); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs * rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs * rhs;
    }
};
template <class T>
struct And {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs & rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs & rhs;
    }
};
template <class T>
struct Or {
    using value_type = T;
    static constexpr T id() { return T(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs | rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs | rhs;
    }
};
template <class T>
struct Xor {
    using value_type = T;
    static constexpr T id() { return T(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs ^ rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs ^ rhs;
    }
};
template <class T>
struct Min {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) { return std::min(lhs, rhs); }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return std::min((U)lhs, rhs);
    }
};
template <class T>
struct Max {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::lowest(); }
    static constexpr T op(const T &lhs, const T &rhs) { return std::max(lhs, rhs); }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return std::max((U)lhs, rhs);
    }
};
template <class T>
struct Gcd {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) {
        return lhs == Gcd::id() ? rhs : (rhs == Gcd::id() ? lhs : std::gcd(lhs, rhs));
    }
};
template <class T>
struct Lcm {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) {
        return lhs == Lcm::id() ? rhs : (rhs == Lcm::id() ? lhs : std::lcm(lhs, rhs));
    }
};
template <class T>
struct Update {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs == Update::id() ? rhs : lhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs == Update::id() ? rhs : lhs;
    }
};
template <class T>
struct Affine {
    using P = std::pair<T, T>;
    using value_type = P;
    static constexpr P id() { return P(1, 0); }
    static constexpr P op(P lhs, P rhs) {
        return {lhs.first * rhs.first, lhs.first * rhs.second + lhs.second};
    }
};
template <class M>
struct Rev {
    using T = typename M::value_type;
    using value_type = T;
    static constexpr T id() { return M::id(); }
    static constexpr T op(T lhs, T rhs) { return M::op(rhs, lhs); }
};
int main(void) {
    int n, q;
    std::cin >> n >> q;
    std::vector<int> a(n);
    for (auto &e : a) std::cin >> e;
    dynamic_sequence<Min<int>> ds;
    for (auto e : a) ds.push_back(e);
    while (q--) {
        int t;
        std::cin >> t;
        if (t == 0) {
            int l, r;
            std::cin >> l >> r, ++r;
            if (l + 1 == r)
                continue;
            auto [lp, mp, rp] = ds.split(l, r);
            auto [lm, rm] = mp.split(r - l - 1);
            rm.merge_right(lm);
            lp.merge_right(rm);
            lp.merge_right(rp);
            ds = lp;
        } else if (t == 1) {
            int l, r;
            std::cin >> l >> r, ++r;
            std::cout << ds.prod(l, r) << '\n';
        } else {
            int k, x;
            std::cin >> k >> x;
            ds.set(k, x);
        }
    }
    return 0;
}
accuracy: 1
time_ms: 340
memory_kb: 13392
final_rank: 7

code_snippet: // competitive-verifier: PROBLEM https://onlinejudge.u-aizu.ac.jp/problems/1508
#include <iostream>
#include <cassert>
#include <random>
#include <tuple>
#include <utility>
/// @brief 動的配列
template <class M, class UniformRandomBitGenerator = std::mt19937>
struct dynamic_sequence {
  private:
    using T = typename M::value_type;
    using priority_type = typename UniformRandomBitGenerator::result_type;
    struct node_t {
        using pointer = node_t *;
        static int count(pointer t) { return !t ? 0 : t->cnt; }
        static T composition(pointer t) { return !t ? M::id() : t->acc; }
        node_t(const T &v, priority_type p)
            : val(v), acc(v), ch{nullptr, nullptr}, priority(p), cnt(1), rev() {}
        node_t(T &&v, priority_type p)
            : val(v), acc(v), ch{nullptr, nullptr}, priority(p), cnt(1), rev() {}
        T val, acc;
        pointer ch[2];
        priority_type priority;
        int cnt;
        bool rev;
    };
    using node_ptr = typename node_t::pointer;
  public:
    dynamic_sequence() : root(nullptr) {}
    dynamic_sequence(node_ptr p) : root(p) {}
    int size() const { return node_t::count(root); }
    T get(int k) const {
        assert(k < node_t::count(root));
        node_ptr node = root;
        while (true) {
            int c = node_t::count(node->ch[0]);
            if (c == k) break;
            if (k < c) node = node->ch[0];
            else node = node->ch[1], k -= c + 1;
        }
        return node->val;
    }
    void insert(int k, T val) { root = insert(root, k, val); }
    void push_front(const T &val) {
        node_ptr node = new node_t(val, gen());
        root = merge(node, root);
    }
    void push_front(T &&val) {
        node_ptr node = new node_t(std::move(val), gen());
        root = merge(node, root);
    }
    void push_back(const T &val) {
        node_ptr node = new node_t(val, gen());
        root = merge(root, node);
    }
    void push_back(T &&val) {
        node_ptr node = new node_t(std::move(val), gen());
        root = merge(root, node);
    }
    void erase(int k) { root = erase(root, k); }
    T prod(int r) const { return prod(root, r); }
    T prod(int l, int r) {
        assert(0 <= l && l <= r && r <= node_t::count(root));
        std::pair<node_ptr, node_ptr> p = split(root, l);
        T res = prod(p.second, r - l);
        root = merge(p.first, p.second);
        return res;
    }
    void reverse(int l, int r) {
        std::pair<node_ptr, node_ptr> sr = split(root, r);
        std::pair<node_ptr, node_ptr> sl = split(sr.first, l);
        if (sl.second) sl.second->rev ^= true;
        root = merge(sl.first, sl.second);
        root = merge(root, sr.second);
    }
    int lower_bound(T key) {
        node_ptr node = root;
        int res = 0;
        while (node) {
            int c = node_t::count(node->ch[0]);
            if (node->acc < key) node = node->ch[1], res += c + 1;
            else node = node->ch[0];
        }
        return res;
    }
    std::pair<dynamic_sequence, dynamic_sequence> split(int k) {
        auto [pl, pr] = split(root, k);
        return std::make_pair(dynamic_sequence(pl), dynamic_sequence(pr));
    }
    std::tuple<dynamic_sequence, dynamic_sequence, dynamic_sequence> split(int l, int r) {
        auto [pl, pr] = split(root, r);
        auto [ql, qr] = split(pl, l);
        return std::make_tuple(dynamic_sequence(ql), dynamic_sequence(qr), dynamic_sequence(pr));
    }
    void merge_left(dynamic_sequence lhs) { root = merge(lhs.root, root); }
    void merge_right(dynamic_sequence rhs) { root = merge(root, rhs.root); }
  private:
    static inline UniformRandomBitGenerator gen = UniformRandomBitGenerator();
    node_ptr root;
    void push(node_ptr t) {
        if (t && t->rev) {
            std::swap(t->ch[0], t->ch[1]);
            if (t->ch[0]) t->ch[0]->rev ^= true;
            if (t->ch[1]) t->ch[1]->rev ^= true;
            t->rev = false;
        }
    }
    node_ptr update(node_ptr t) {
        push(t);
        t->cnt = node_t::count(t->ch[0]) + node_t::count(t->ch[1]) + 1;
        t->acc = M::op(M::op(node_t::composition(t->ch[0]), t->val), node_t::composition(t->ch[1]));
        return t;
    }
    node_ptr merge(node_ptr l, node_ptr r) {
        if (!l || !r) return !l ? r : l;
        push(l);
        push(r);
        if (l->priority > r->priority) {
            l->ch[1] = merge(l->ch[1], r);
            return update(l);
        } else {
            r->ch[0] = merge(l, r->ch[0]);
            return update(r);
        }
    }
    std::pair<node_ptr, node_ptr> split(node_ptr t, int k) {
        if (!t) return std::make_pair<node_ptr, node_ptr>(nullptr, nullptr);
        push(t);
        if (k <= node_t::count(t->ch[0])) {
            auto s = split(t->ch[0], k);
            t->ch[0] = s.second;
            return std::make_pair(s.first, update(t));
        } else {
            auto s = split(t->ch[1], k - node_t::count(t->ch[0]) - 1);
            t->ch[1] = s.first;
            return std::make_pair(update(t), s.second);
        }
    }
    node_ptr insert(node_ptr t, int k, T v) {
        std::pair<node_ptr, node_ptr> s = split(t, k);
        node_ptr res = new node_t(v, gen());
        res = merge(s.first, res);
        res = merge(res, s.second);
        return res;
    }
    node_ptr erase(node_ptr t, int k) {
        int c = node_t::count(t->ch[0]);
        if (k == c) return merge(t->ch[0], t->ch[1]);
        if (k < c) {
            t->ch[0] = erase(t->ch[0], k);
            return update(t);
        } else {
            t->ch[1] = erase(t->ch[1], k - c - 1);
            return update(t);
        }
    }
    T prod(node_ptr t, int r) const {
        assert(0 <= r && r <= node_t::count(t));
        T res = M::id();
        while (r) {
            if (r == node_t::count(t)) {
                res = M::op(res, node_t::composition(t));
                break;
            }
            int c = node_t::count(t->ch[0]);
            if (r < c) {
                t = t->ch[0];
                continue;
            }
            res = M::op(res, node_t::composition(t->ch[0]));
            r -= c;
            if (r) res = M::op(res, t->val), --r;
            t = t->ch[1];
        }
        return res;
    }
};
#include <algorithm>
#include <limits>
#include <numeric>
template <class T>
struct Add {
    using value_type = T;
    static constexpr T id() { return T(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs + rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs + rhs;
    }
};
template <class T>
struct Mul {
    using value_type = T;
    static constexpr T id() { return T(1); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs * rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs * rhs;
    }
};
template <class T>
struct And {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs & rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs & rhs;
    }
};
template <class T>
struct Or {
    using value_type = T;
    static constexpr T id() { return T(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs | rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs | rhs;
    }
};
template <class T>
struct Xor {
    using value_type = T;
    static constexpr T id() { return T(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs ^ rhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs ^ rhs;
    }
};
template <class T>
struct Min {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) { return std::min(lhs, rhs); }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return std::min((U)lhs, rhs);
    }
};
template <class T>
struct Max {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::lowest(); }
    static constexpr T op(const T &lhs, const T &rhs) { return std::max(lhs, rhs); }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return std::max((U)lhs, rhs);
    }
};
template <class T>
struct Gcd {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) {
        return lhs == Gcd::id() ? rhs : (rhs == Gcd::id() ? lhs : std::gcd(lhs, rhs));
    }
};
template <class T>
struct Lcm {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) {
        return lhs == Lcm::id() ? rhs : (rhs == Lcm::id() ? lhs : std::lcm(lhs, rhs));
    }
};
template <class T>
struct Update {
    using value_type = T;
    static constexpr T id() { return std::numeric_limits<T>::max(); }
    static constexpr T op(const T &lhs, const T &rhs) { return lhs == Update::id() ? rhs : lhs; }
    template <class U>
    static constexpr U f(T lhs, U rhs) {
        return lhs == Update::id() ? rhs : lhs;
    }
};
template <class T>
struct Affine {
    using P = std::pair<T, T>;
    using value_type = P;
    static constexpr P id() { return P(1, 0); }
    static constexpr P op(P lhs, P rhs) {
        return {lhs.first * rhs.first, lhs.first * rhs.second + lhs.second};
    }
};
template <class M>
struct Rev {
    using T = typename M::value_type;
    using value_type = T;
    static constexpr T id() { return M::id(); }
    static constexpr T op(T lhs, T rhs) { return M::op(rhs, lhs); }
};
int main(void) {
    int n, q;
    std::cin >> n >> q;
    std::vector<int> a(n);
    for (auto &e : a) std::cin >> e;
    dynamic_sequence<Min<int>> ds;
    for (auto e : a) ds.push_back(e);
    while (q--) {
        int t;
        std::cin >> t;
        if (t == 0) {
            int l, r;
            std::cin >> l >> r, ++r;
            if (l + 1 == r)
                continue;
            auto [lp, mp, rp] = ds.split(l, r);
            auto [lm, rm] = mp.split(r - l - 1);
            rm.merge_right(lm);
            lp.merge_right(rm);
            lp.merge_right(rp);
            ds = lp;
        } else if (t == 1) {
            int l, r;
            std::cin >> l >> r, ++r;
            std::cout << ds.prod(l, r) << '\n';
        } else {
            int k, x;
            std::cin >> k >> x;
            ds.erase(k);
            ds.insert(k, x);
        }
    }
    return 0;
}
accuracy: 1
time_ms: 370
memory_kb: 16292
final_rank: 9

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define itn int
#define rep(i,n) for(long long i=0;i<(long long)n;i++)
#define reps(i,n) for(long long i=1;i<=(long long)n;i++)
#define repi(i,n) for(int i=0;i<(int)n;i++)
#define loop(i,l,r) for(long long i=(long long)l;i<=(long long)r;i++)
#define loopi(i,l,r) for(int i=(int)l;i<=(int)r;i++)
#define drep(i,n) for(long long i=(long long)n-1;i>=0;i--)
#define drepi(i,n) for(int i=(int)n-1;i>=0;i--)
#define dreps(i,n) for(int i=(int)n;i>=1;i--)
#define dloop(i,l,r) for(long long i=(long long)l;i>=(long long)r;i--)
#define dloopi(i,l,r) for(int i=(int)l;i>=(int)r;i--)
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(), v.rend()
#define yn(x) cout << (x? "Yes":"No") << endl;
#define cou(x) cout << x << endl;
#define emp emplace_back
#pragma GCC target ("avx,avx2")//四則演算
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")//ループ
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")//浮動小数点
const long long mod=998244353LL;
const long long mods=1000000007LL;
const double inf=numeric_limits<double>::infinity();
const int kaz=1000000005;
const long long yab=2500000000000000000LL;
const long long aho =-yab;
const long double eps=1.0e-14L;
const long double pi=acosl(-1.0L);
using ll=long long;
using st=string;
using P=pair<ll,ll>;
using tup=tuple<ll,ll,ll>;
using vi=vector<ll>;
using vin=vector<int>;
using vc=vector<char>;
using vb=vector<bool>;
using vd=vector<double>;
using vs=vector<string>;
using vp=vector<P>;
using sp=set<P>;
using si=set<ll>;
using vvi=vector<vector<ll>>;
using vvin=vector<vin>;
using vvc=vector<vc>;
using vvb=vector<vb>;
using vvvi=vector<vvi>;
using vvvin=vector<vvin>;
const int dx[4]={0,1,0,-1};
const int dy[4]={1,0,-1,0};
const vector<int> ex = {-1, -1, -1, 0, 0, 1, 1, 1};
const vector<int> ey = {-1, 0, 1, -1, 1, -1, 0, 1};
template<typename T>istream&operator>>(istream&is,vector<T>&v){for(T&in:v)is>>in;return is;}
template<typename T>ostream&operator<<(ostream&os,vector<T>v){rep(i,v.size())os<<v[i]<<(i+1!=v.size()?" ":"\n");return os;}
template<typename T1,typename T2>
void co(bool x,T1 y,T2 z){
  if(x)cout << y << endl;
  else cout << z << endl;
}
template<typename T>
bool chmax(T &a, T b){
	if(a<b){
		a=b;
		return true;
	}
	return false;
}
template <typename T, typename U>
T ceil(T x, U y) {
  return (x > 0 ? (x + y - 1) / y : x / y);
}

template <typename T, typename U>
T floor(T x, U y) {
  return (x > 0 ? x / y : (x - y + 1) / y);
}
template<typename T>
bool chmin(T &a, T b){
	if(a>b){
		a=b;
		return true;
	}
	return false;
}
template<typename T>
void print(vector<T> &a){
	for(int i=0;i<a.size();i++){
		cout << a[i];
		if(i==(long long)a.size()-1)cout << endl;
		else cout << " ";
	}
}
template<typename T>
void her(vector<T> &a){
  for(auto &g:a)g--;
}
vector<long long> fac,finv,invs;
// テーブルを作る前処理
void COMinit(int MAX,int MOD) {
	fac.resize(MAX);
	finv.resize(MAX);
	invs.resize(MAX);
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    invs[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD;
        invs[i] = MOD - invs[MOD%i] * (MOD / i) % MOD;
        finv[i] = finv[i - 1] * invs[i] % MOD;
    }
}

// 二項係数計算
long long COM(int n, int k,int MOD){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}
ll mypow(ll x,ll y){
	ll ret=1;
	while(y>0){
		if(y&1)ret=ret*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ret;
}
ll nopow(ll x,ll y){
	ll ret=1;
	while(y>0){
		if(y&1)ret*=x;
		x*=x;
		y>>=1;
	}
	return ret;
}
//imprict treap
// T0: 元の配列のモノイド
// T1: T0に対する作用素モノイド
template <class T0, class T1>
class BaseImplicitTreap {
    // T0上の演算、単位元
    virtual T0 f0(T0, T0) = 0;
    const T0 u0;
    // T1上の演算、単位元
    virtual T1 f1(T1, T1) = 0;
    const T1 u1;
    // T0に対するT1の作用
    virtual T0 g(T0, T1) = 0;
    // 多数のt1(T1)に対するf1の合成
    virtual T1 p(T1, int) = 0;

    class xorshift {
        uint64_t x;

    public:
        xorshift() {
            mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
            x = rnd();
            for (int i = 0; i < 100; i++) {
                random();
            }
        }

        uint64_t random() {
            x = x ^ (x << 7);
            return x = x ^ (x >> 9);
        }
    } rnd;

    struct Node {
        T0 value, acc;
        T1 lazy;
        int priority, cnt;
        bool rev;
        Node *l, *r;

        Node(T0 value_, int priority_, T0 u0_, T1 u1_)
            : value(value_), acc(u0_), lazy(u1_), priority(priority_), cnt(1), rev(false), l(nullptr), r(nullptr) {}
    } *root = nullptr;

    using Tree = Node *;

    int cnt(Tree t) { return t ? t->cnt : 0; }

    T0 acc(Tree t) { return t ? t->acc : u0; }

    void update_cnt(Tree t) {
        if (t) {
            t->cnt = 1 + cnt(t->l) + cnt(t->r);
        }
    }

    void update_acc(Tree t) {
        if (t) {
            t->acc = f0(acc(t->l), f0(t->value, acc(t->r)));
        }
    }

    void pushup(Tree t) { update_cnt(t), update_acc(t); }

    void pushdown(Tree t) {
        if (t && t->rev) {
            t->rev = false;
            swap(t->l, t->r);
            if (t->l) t->l->rev ^= 1;
            if (t->r) t->r->rev ^= 1;
        }
        if (t && t->lazy != u1) {
            if (t->l) {
                t->l->lazy = f1(t->l->lazy, t->lazy);
                t->l->acc = g(t->l->acc, p(t->lazy, cnt(t->l)));
            }
            if (t->r) {
                t->r->lazy = f1(t->r->lazy, t->lazy);
                t->r->acc = g(t->r->acc, p(t->lazy, cnt(t->r)));
            }
            t->value = g(t->value, p(t->lazy, 1));
            t->lazy = u1;
        }
        pushup(t);
    }

    void split(Tree t, int key, Tree &l, Tree &r) {
        if (!t) {
            l = r = nullptr;
            return;
        }
        pushdown(t);
        int implicit_key = cnt(t->l) + 1;
        if (key < implicit_key) {
            split(t->l, key, l, t->l), r = t;
        } else {
            split(t->r, key - implicit_key, t->r, r), l = t;
        }
        pushup(t);
    }

    void insert(Tree &t, int key, Tree item) {
        Tree t1, t2;
        split(t, key, t1, t2);
        merge(t1, t1, item);
        merge(t, t1, t2);
    }

    void merge(Tree &t, Tree l, Tree r) {
        pushdown(l);
        pushdown(r);
        if (!l || !r) {
            t = l ? l : r;
        } else if (l->priority > r->priority) {
            merge(l->r, l->r, r), t = l;
        } else {
            merge(r->l, l, r->l), t = r;
        }
        pushup(t);
    }

    void erase(Tree &t, int key) {
        Tree t1, t2, t3;
        split(t, key + 1, t1, t2);
        split(t1, key, t1, t3);
        merge(t, t1, t2);
    }

    void update(Tree t, int l, int r, T1 x) {
        if (l >= r) return;
        Tree t1, t2, t3;
        split(t, l, t1, t2);
        split(t2, r - l, t2, t3);
        t2->lazy = f1(t2->lazy, x);
        t2->acc = g(t2->acc, p(x, cnt(t2)));
        merge(t2, t2, t3);
        merge(t, t1, t2);
    }

    T0 query(Tree t, int l, int r) {
        if (l == r) return u0;
        Tree t1, t2, t3;
        split(t, l, t1, t2);
        split(t2, r - l, t2, t3);
        T0 ret = t2->acc;
        merge(t2, t2, t3);
        merge(t, t1, t2);
        return ret;
    }

    // [l, r)の中で左から何番目か
    int find(Tree t, T0 x, int offset, bool left = true) {
        if (f0(t->acc, x) == x) {
            return -1;
        } else {
            if (left) {
                if (t->l && f0(t->l->acc, x) != x) {
                    return find(t->l, x, offset, left);
                } else {
                    return (f0(t->value, x) != x) ? offset + cnt(t->l) : find(t->r, x, offset + cnt(t->l) + 1, left);
                }
            } else {
                if (t->r && f0(t->r->acc, x) != x) {
                    return find(t->r, x, offset + cnt(t->l) + 1, left);
                } else {
                    return (f0(t->value, x) != x) ? offset + cnt(t->l) : find(t->l, x, offset, left);
                }
            }
        }
    }

    void reverse(Tree t, int l, int r) {
        if (l > r) return;
        Tree t1, t2, t3;
        split(t, l, t1, t2);
        split(t2, r - l, t2, t3);
        t2->rev ^= 1;
        merge(t2, t2, t3);
        merge(t, t1, t2);
    }

    // [l, r)の先頭がmになるようにシフトさせる。std::rotateと同じ仕様
    void rotate(Tree t, int l, int m, int r) {
        reverse(t, l, r);
        reverse(t, l, l + r - m);
        reverse(t, l + r - m, r);
    }

    void dump(Tree t) {
        if (!t) return;
        pushdown(t);
        dump(t->l);
        cout << t->value << " ";
        dump(t->r);
    }

public:
    BaseImplicitTreap(T0 u0_, T1 u1_) : u0(u0_), u1(u1_) {}

    void set_by_vector(const vector<T0> &a) {
        for (int i = 0; i < a.size(); i++) {
            insert(i, a[i]);
        }
    }

    int size() { return cnt(root); }

    void insert(int pos, T0 x) { insert(root, pos, new Node(x, rnd.random(), u0, u1)); }

    void update(int l, int r, T1 x) { update(root, l, r, x); }

    T0 query(int l, int r) { return query(root, l, r); }

    // 二分探索。[l, r)内のkでf0(tr[k], x) != xとなる最左/最右のもの。存在しない場合は-1
    // たとえばMinMonoidの場合、x未満の最左/最右の要素の位置を返す
    int binary_search(int l, int r, T0 x, bool left = true) {
        if (l >= r) return -1;
        Tree t1, t2, t3;
        split(root, l, t1, t2);
        split(t2, r - l, t2, t3);
        int ret = find(t2, x, l, left);
        merge(t2, t2, t3);
        merge(root, t1, t2);
        return ret;
    }

    void erase(int pos) { erase(root, pos); }

    void reverse(int l, int r) { reverse(root, l, r); }

    void rotate(int l, int m, int r) { rotate(root, l, m, r); }

    void dump() {
        dump(root);
        cout << endl;
    }

    T0 operator[](int pos) { return query(pos, pos + 1); }
};

template <class T0, class T1>
struct MinUpdateQuery : public BaseImplicitTreap<T0, T1> {
    using BaseImplicitTreap<T0, T1>::BaseImplicitTreap;
    MinUpdateQuery() : MinUpdateQuery(numeric_limits<T0>::max(), numeric_limits<T1>::min()) {}
    T0 f0(T0 x, T0 y) override { return min(x, y); }
    T1 f1(T1 x, T1 y) override { return y == numeric_limits<T1>::min() ? x : y; }
    T0 g(T0 x, T1 y) override { return y == numeric_limits<T1>::min() ? x : y; }
    T1 p(T1 x, int len) override { return x; }
};

template <class T0, class T1>
struct SumAddQuery : public BaseImplicitTreap<T0, T1> {
    using BaseImplicitTreap<T0, T1>::BaseImplicitTreap;
    SumAddQuery() : SumAddQuery(0, 0) {}
    T0 f0(T0 x, T0 y) override { return x + y; }
    T1 f1(T1 x, T1 y) override { return x + y; }
    T0 g(T0 x, T1 y) override { return x + y; }
    T1 p(T1 x, int len) override { return x * len; }
};

template <class T0, class T1>
struct MinAddQuery : public BaseImplicitTreap<T0, T1> {
    using BaseImplicitTreap<T0, T1>::BaseImplicitTreap;
    MinAddQuery() : MinAddQuery(numeric_limits<T0>::max(), 0) {}
    T0 f0(T0 x, T0 y) override { return min(x, y); }
    T1 f1(T1 x, T1 y) override { return x + y; }
    T0 g(T0 x, T1 y) override { return x + y; }
    T1 p(T1 x, int len) override { return x; }
};

template <class T0, class T1>
struct SumUpdateQuery : public BaseImplicitTreap<T0, T1> {
    using BaseImplicitTreap<T0, T1>::BaseImplicitTreap;
    SumUpdateQuery() : SumUpdateQuery(0, numeric_limits<T1>::min()) {}
    T0 f0(T0 x, T0 y) override { return x + y; }
    T1 f1(T1 x, T1 y) override { return y == numeric_limits<T1>::min() ? x : y; }
    T0 g(T0 x, T1 y) override { return y == numeric_limits<T1>::min() ? x : y; }
    T1 p(T1 x, int len) override { return x == numeric_limits<T1>::min() ? numeric_limits<T1>::min() : x * len; }
};

template <class T0>
struct SumAffineQuery : public BaseImplicitTreap<T0, pair<T0, T0>> {
    using T1 = pair<T0, T0>;  // first * x + second
    using BaseImplicitTreap<T0, T1>::BaseImplicitTreap;
    SumAffineQuery() : SumAffineQuery(0, {1, 0}) {}
    T0 f0(T0 x, T0 y) override { return x + y; }
    T1 f1(T1 x, T1 y) override { return {x.first * y.first, x.second * y.first + y.second}; }
    T0 g(T0 x, T1 y) override { return y.first * x + y.second; }
    T1 p(T1 x, int len) override { return {x.first, x.second * len}; }
    // update(i, j, {a, b}); // [i, j)にax + bを作用
    // update(i, j, {0, a}); // update
    // update(i, j, {1, a}); // 加算
    // update(i, j, {a, 0}); // 倍
};

template <class T>
struct MinmaxAffineQuery : public BaseImplicitTreap<pair<T, T>, pair<T, T>> {
    using T0 = pair<T, T>;  // {min, max}
    using T1 = pair<T, T>;  // first * x + second
    using BaseImplicitTreap<T0, T1>::BaseImplicitTreap;
    MinmaxAffineQuery()
        : MinmaxAffineQuery({numeric_limits<T>::max(), -numeric_limits<T>::max()}, {1, 0}) {
    }  // TODO: _u1を使うとコンパイル通らない原因不明
    T0 f0(T0 x, T0 y) override { return {min(x.first, y.first), max(x.second, y.second)}; }
    T1 f1(T1 x, T1 y) override { return {x.first * y.first, x.second * y.first + y.second}; }
    T0 g(T0 x, T1 y) override {
        T0 ret = {x.first * y.first + y.second, x.second * y.first + y.second};
        if (y.first < 0) swap(ret.first, ret.second);
        return ret;
    }
    T1 p(T1 x, int len) override { return x; }
    // update(i, j, {a, b}); // [i, j)にax + bを作用
    // update(i, j, {0, a}); // update
    // update(i, j, {1, a}); // 加算
    // update(i, j, {a, 0}); // 倍
};
int main(){
	cin.tie(nullptr);
	int n,q;
    cin >> n >> q;
    vi a(n);
    cin >> a;
    MinAddQuery<ll,ll> s;
    s.set_by_vector(a);
    while(q--){
        ll t,x,y;
        cin >> t >> x >> y;
        if(t==0){
            s.rotate(x,y,y+1);
        }
        if(t==1){
            cout << s.query(x,y+1) << endl;
        }
        if(t==2){
            s.update(x,x+1,y-s[x]);
        }
    }
}
accuracy: 1
time_ms: 480
memory_kb: 17536
final_rank: 15

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define itn int
#define rep(i,n) for(long long i=0;i<(long long)n;i++)
#define reps(i,n) for(long long i=1;i<=(long long)n;i++)
#define repi(i,n) for(int i=0;i<(int)n;i++)
#define loop(i,l,r) for(long long i=(long long)l;i<=(long long)r;i++)
#define loopi(i,l,r) for(int i=(int)l;i<=(int)r;i++)
#define drep(i,n) for(long long i=(long long)n-1;i>=0;i--)
#define drepi(i,n) for(int i=(int)n-1;i>=0;i--)
#define dreps(i,n) for(int i=(int)n;i>=1;i--)
#define dloop(i,l,r) for(long long i=(long long)l;i>=(long long)r;i--)
#define dloopi(i,l,r) for(int i=(int)l;i>=(int)r;i--)
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(), v.rend()
#define yn(x) cout << (x? "Yes":"No") << endl;
#define cou(x) cout << x << endl;
#define emp emplace_back
#pragma GCC target ("avx,avx2")//四則演算
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")//ループ
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")//浮動小数点
const long long mod=998244353LL;
const long long mods=1000000007LL;
const double inf=numeric_limits<double>::infinity();
const int kaz=1000000005;
const long long yab=2500000000000000000LL;
const long long aho =-yab;
const long double eps=1.0e-14L;
const long double pi=acosl(-1.0L);
using ll=long long;
using st=string;
using P=pair<ll,ll>;
using tup=tuple<ll,ll,ll>;
using vi=vector<ll>;
using vin=vector<int>;
using vc=vector<char>;
using vb=vector<bool>;
using vd=vector<double>;
using vs=vector<string>;
using vp=vector<P>;
using sp=set<P>;
using si=set<ll>;
using vvi=vector<vector<ll>>;
using vvin=vector<vin>;
using vvc=vector<vc>;
using vvb=vector<vb>;
using vvvi=vector<vvi>;
using vvvin=vector<vvin>;
const int dx[4]={0,1,0,-1};
const int dy[4]={1,0,-1,0};
const vector<int> ex = {-1, -1, -1, 0, 0, 1, 1, 1};
const vector<int> ey = {-1, 0, 1, -1, 1, -1, 0, 1};
template<typename T>istream&operator>>(istream&is,vector<T>&v){for(T&in:v)is>>in;return is;}
template<typename T>ostream&operator<<(ostream&os,vector<T>v){rep(i,v.size())os<<v[i]<<(i+1!=v.size()?" ":"\n");return os;}
template<typename T1,typename T2>
void co(bool x,T1 y,T2 z){
  if(x)cout << y << endl;
  else cout << z << endl;
}
template<typename T>
bool chmax(T &a, T b){
	if(a<b){
		a=b;
		return true;
	}
	return false;
}
template <typename T, typename U>
T ceil(T x, U y) {
  return (x > 0 ? (x + y - 1) / y : x / y);
}

template <typename T, typename U>
T floor(T x, U y) {
  return (x > 0 ? x / y : (x - y + 1) / y);
}
template<typename T>
bool chmin(T &a, T b){
	if(a>b){
		a=b;
		return true;
	}
	return false;
}
template<typename T>
void print(vector<T> &a){
	for(int i=0;i<a.size();i++){
		cout << a[i];
		if(i==(long long)a.size()-1)cout << endl;
		else cout << " ";
	}
}
template<typename T>
void her(vector<T> &a){
  for(auto &g:a)g--;
}
vector<long long> fac,finv,invs;
// テーブルを作る前処理
void COMinit(int MAX,int MOD) {
	fac.resize(MAX);
	finv.resize(MAX);
	invs.resize(MAX);
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    invs[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD;
        invs[i] = MOD - invs[MOD%i] * (MOD / i) % MOD;
        finv[i] = finv[i - 1] * invs[i] % MOD;
    }
}

// 二項係数計算
long long COM(int n, int k,int MOD){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}
ll mypow(ll x,ll y){
	ll ret=1;
	while(y>0){
		if(y&1)ret=ret*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ret;
}
ll nopow(ll x,ll y){
	ll ret=1;
	while(y>0){
		if(y&1)ret*=x;
		x*=x;
		y>>=1;
	}
	return ret;
}
//imprict treap
// T0: 元の配列のモノイド
// T1: T0に対する作用素モノイド
template <class T0, class T1>
class BaseImplicitTreap {
    // T0上の演算、単位元
    virtual T0 f0(T0, T0) = 0;
    const T0 u0;
    // T1上の演算、単位元
    virtual T1 f1(T1, T1) = 0;
    const T1 u1;
    // T0に対するT1の作用
    virtual T0 g(T0, T1) = 0;
    // 多数のt1(T1)に対するf1の合成
    virtual T1 p(T1, int) = 0;

    class xorshift {
        uint64_t x;

    public:
        xorshift() {
            mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
            x = rnd();
            for (int i = 0; i < 100; i++) {
                random();
            }
        }

        uint64_t random() {
            x = x ^ (x << 7);
            return x = x ^ (x >> 9);
        }
    } rnd;

    struct Node {
        T0 value, acc;
        T1 lazy;
        int priority, cnt;
        bool rev;
        Node *l, *r;

        Node(T0 value_, int priority_, T0 u0_, T1 u1_)
            : value(value_), acc(u0_), lazy(u1_), priority(priority_), cnt(1), rev(false), l(nullptr), r(nullptr) {}
    } *root = nullptr;

    using Tree = Node *;

    int cnt(Tree t) { return t ? t->cnt : 0; }

    T0 acc(Tree t) { return t ? t->acc : u0; }

    void update_cnt(Tree t) {
        if (t) {
            t->cnt = 1 + cnt(t->l) + cnt(t->r);
        }
    }

    void update_acc(Tree t) {
        if (t) {
            t->acc = f0(acc(t->l), f0(t->value, acc(t->r)));
        }
    }

    void pushup(Tree t) { update_cnt(t), update_acc(t); }

    void pushdown(Tree t) {
        if (t && t->rev) {
            t->rev = false;
            swap(t->l, t->r);
            if (t->l) t->l->rev ^= 1;
            if (t->r) t->r->rev ^= 1;
        }
        if (t && t->lazy != u1) {
            if (t->l) {
                t->l->lazy = f1(t->l->lazy, t->lazy);
                t->l->acc = g(t->l->acc, p(t->lazy, cnt(t->l)));
            }
            if (t->r) {
                t->r->lazy = f1(t->r->lazy, t->lazy);
                t->r->acc = g(t->r->acc, p(t->lazy, cnt(t->r)));
            }
            t->value = g(t->value, p(t->lazy, 1));
            t->lazy = u1;
        }
        pushup(t);
    }

    void split(Tree t, int key, Tree &l, Tree &r) {
        if (!t) {
            l = r = nullptr;
            return;
        }
        pushdown(t);
        int implicit_key = cnt(t->l) + 1;
        if (key < implicit_key) {
            split(t->l, key, l, t->l), r = t;
        } else {
            split(t->r, key - implicit_key, t->r, r), l = t;
        }
        pushup(t);
    }

    void insert(Tree &t, int key, Tree item) {
        Tree t1, t2;
        split(t, key, t1, t2);
        merge(t1, t1, item);
        merge(t, t1, t2);
    }

    void merge(Tree &t, Tree l, Tree r) {
        pushdown(l);
        pushdown(r);
        if (!l || !r) {
            t = l ? l : r;
        } else if (l->priority > r->priority) {
            merge(l->r, l->r, r), t = l;
        } else {
            merge(r->l, l, r->l), t = r;
        }
        pushup(t);
    }

    void erase(Tree &t, int key) {
        Tree t1, t2, t3;
        split(t, key + 1, t1, t2);
        split(t1, key, t1, t3);
        merge(t, t1, t2);
    }

    void update(Tree t, int l, int r, T1 x) {
        if (l >= r) return;
        Tree t1, t2, t3;
        split(t, l, t1, t2);
        split(t2, r - l, t2, t3);
        t2->lazy = f1(t2->lazy, x);
        t2->acc = g(t2->acc, p(x, cnt(t2)));
        merge(t2, t2, t3);
        merge(t, t1, t2);
    }

    T0 query(Tree t, int l, int r) {
        if (l == r) return u0;
        Tree t1, t2, t3;
        split(t, l, t1, t2);
        split(t2, r - l, t2, t3);
        T0 ret = t2->acc;
        merge(t2, t2, t3);
        merge(t, t1, t2);
        return ret;
    }

    // [l, r)の中で左から何番目か
    int find(Tree t, T0 x, int offset, bool left = true) {
        if (f0(t->acc, x) == x) {
            return -1;
        } else {
            if (left) {
                if (t->l && f0(t->l->acc, x) != x) {
                    return find(t->l, x, offset, left);
                } else {
                    return (f0(t->value, x) != x) ? offset + cnt(t->l) : find(t->r, x, offset + cnt(t->l) + 1, left);
                }
            } else {
                if (t->r && f0(t->r->acc, x) != x) {
                    return find(t->r, x, offset + cnt(t->l) + 1, left);
                } else {
                    return (f0(t->value, x) != x) ? offset + cnt(t->l) : find(t->l, x, offset, left);
                }
            }
        }
    }

    void reverse(Tree t, int l, int r) {
        if (l > r) return;
        Tree t1, t2, t3;
        split(t, l, t1, t2);
        split(t2, r - l, t2, t3);
        t2->rev ^= 1;
        merge(t2, t2, t3);
        merge(t, t1, t2);
    }

    // [l, r)の先頭がmになるようにシフトさせる。std::rotateと同じ仕様
    void rotate(Tree t, int l, int m, int r) {
        reverse(t, l, r);
        reverse(t, l, l + r - m);
        reverse(t, l + r - m, r);
    }

    void dump(Tree t) {
        if (!t) return;
        pushdown(t);
        dump(t->l);
        cout << t->value << " ";
        dump(t->r);
    }

public:
    BaseImplicitTreap(T0 u0_, T1 u1_) : u0(u0_), u1(u1_) {}

    void set_by_vector(const vector<T0> &a) {
        for (int i = 0; i < a.size(); i++) {
            insert(i, a[i]);
        }
    }

    int size() { return cnt(root); }

    void insert(int pos, T0 x) { insert(root, pos, new Node(x, rnd.random(), u0, u1)); }

    void update(int l, int r, T1 x) { update(root, l, r, x); }

    T0 query(int l, int r) { return query(root, l, r); }

    // 二分探索。[l, r)内のkでf0(tr[k], x) != xとなる最左/最右のもの。存在しない場合は-1
    // たとえばMinMonoidの場合、x未満の最左/最右の要素の位置を返す
    int binary_search(int l, int r, T0 x, bool left = true) {
        if (l >= r) return -1;
        Tree t1, t2, t3;
        split(root, l, t1, t2);
        split(t2, r - l, t2, t3);
        int ret = find(t2, x, l, left);
        merge(t2, t2, t3);
        merge(root, t1, t2);
        return ret;
    }

    void erase(int pos) { erase(root, pos); }

    void reverse(int l, int r) { reverse(root, l, r); }

    void rotate(int l, int m, int r) { rotate(root, l, m, r); }

    void dump() {
        dump(root);
        cout << endl;
    }

    T0 operator[](int pos) { return query(pos, pos + 1); }
};

template <class T0, class T1>
struct MinUpdateQuery : public BaseImplicitTreap<T0, T1> {
    using BaseImplicitTreap<T0, T1>::BaseImplicitTreap;
    MinUpdateQuery() : MinUpdateQuery(numeric_limits<T0>::max(), numeric_limits<T1>::min()) {}
    T0 f0(T0 x, T0 y) override { return min(x, y); }
    T1 f1(T1 x, T1 y) override { return y == numeric_limits<T1>::min() ? x : y; }
    T0 g(T0 x, T1 y) override { return y == numeric_limits<T1>::min() ? x : y; }
    T1 p(T1 x, int len) override { return x; }
};

template <class T0, class T1>
struct SumAddQuery : public BaseImplicitTreap<T0, T1> {
    using BaseImplicitTreap<T0, T1>::BaseImplicitTreap;
    SumAddQuery() : SumAddQuery(0, 0) {}
    T0 f0(T0 x, T0 y) override { return x + y; }
    T1 f1(T1 x, T1 y) override { return x + y; }
    T0 g(T0 x, T1 y) override { return x + y; }
    T1 p(T1 x, int len) override { return x * len; }
};

template <class T0, class T1>
struct MinAddQuery : public BaseImplicitTreap<T0, T1> {
    using BaseImplicitTreap<T0, T1>::BaseImplicitTreap;
    MinAddQuery() : MinAddQuery(numeric_limits<T0>::max(), 0) {}
    T0 f0(T0 x, T0 y) override { return min(x, y); }
    T1 f1(T1 x, T1 y) override { return x + y; }
    T0 g(T0 x, T1 y) override { return x + y; }
    T1 p(T1 x, int len) override { return x; }
};

template <class T0, class T1>
struct SumUpdateQuery : public BaseImplicitTreap<T0, T1> {
    using BaseImplicitTreap<T0, T1>::BaseImplicitTreap;
    SumUpdateQuery() : SumUpdateQuery(0, numeric_limits<T1>::min()) {}
    T0 f0(T0 x, T0 y) override { return x + y; }
    T1 f1(T1 x, T1 y) override { return y == numeric_limits<T1>::min() ? x : y; }
    T0 g(T0 x, T1 y) override { return y == numeric_limits<T1>::min() ? x : y; }
    T1 p(T1 x, int len) override { return x == numeric_limits<T1>::min() ? numeric_limits<T1>::min() : x * len; }
};

template <class T0>
struct SumAffineQuery : public BaseImplicitTreap<T0, pair<T0, T0>> {
    using T1 = pair<T0, T0>;  // first * x + second
    using BaseImplicitTreap<T0, T1>::BaseImplicitTreap;
    SumAffineQuery() : SumAffineQuery(0, {1, 0}) {}
    T0 f0(T0 x, T0 y) override { return x + y; }
    T1 f1(T1 x, T1 y) override { return {x.first * y.first, x.second * y.first + y.second}; }
    T0 g(T0 x, T1 y) override { return y.first * x + y.second; }
    T1 p(T1 x, int len) override { return {x.first, x.second * len}; }
    // update(i, j, {a, b}); // [i, j)にax + bを作用
    // update(i, j, {0, a}); // update
    // update(i, j, {1, a}); // 加算
    // update(i, j, {a, 0}); // 倍
};

template <class T>
struct MinmaxAffineQuery : public BaseImplicitTreap<pair<T, T>, pair<T, T>> {
    using T0 = pair<T, T>;  // {min, max}
    using T1 = pair<T, T>;  // first * x + second
    using BaseImplicitTreap<T0, T1>::BaseImplicitTreap;
    MinmaxAffineQuery()
        : MinmaxAffineQuery({numeric_limits<T>::max(), -numeric_limits<T>::max()}, {1, 0}) {
    }  // TODO: _u1を使うとコンパイル通らない原因不明
    T0 f0(T0 x, T0 y) override { return {min(x.first, y.first), max(x.second, y.second)}; }
    T1 f1(T1 x, T1 y) override { return {x.first * y.first, x.second * y.first + y.second}; }
    T0 g(T0 x, T1 y) override {
        T0 ret = {x.first * y.first + y.second, x.second * y.first + y.second};
        if (y.first < 0) swap(ret.first, ret.second);
        return ret;
    }
    T1 p(T1 x, int len) override { return x; }
    // update(i, j, {a, b}); // [i, j)にax + bを作用
    // update(i, j, {0, a}); // update
    // update(i, j, {1, a}); // 加算
    // update(i, j, {a, 0}); // 倍
};
int main(){
	cin.tie(nullptr);
	int n,q;
    cin >> n >> q;
    vi a(n);
    cin >> a;
    MinUpdateQuery<ll,ll> s;
    s.set_by_vector(a);
    while(q--){
        ll t,x,y;
        cin >> t >> x >> y;
        if(t==0){
            s.rotate(x,y,y+1);
        }
        if(t==1){
            cout << s.query(x,y+1) << endl;
        }
        if(t==2){
            s.update(x,x+1,y);
        }
    }
}
accuracy: 1
time_ms: 450
memory_kb: 17536
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int, int>
#define pll pair<ll, ll>
#define vi vector<int>
#define vl vector<ll>
#define ov3(a, b, c, name, ...) name
#define rep0(n) for(ll aaaaa = 0; aaaaa < n; ++aaaaa)
#define rep1(i, n) for(ll i = 0; i < (n); i++)
#define rep2(i, a, b) for(ll i = (a); i < (b); i++)
#define rep(...) ov3(__VA_ARGS__, rep2, rep1, rep0)(__VA_ARGS__)
#define per(i, a, b) for(ll i = (a) - 1; i >= (b); i--)
#define all(a) begin(a), end(a)
#define si(a) (int)(size(a))
#define lb(v, x) (lower_bound(all(v), x) - begin(v))
#define eb emplace_back
// bool chmin(auto &a, auto b) { return a > b ? a = b, 1 : 0; }
// bool chmax(auto &a, auto b) { return a < b ? a = b, 1 : 0; }

const int INF = 1e9 + 100;
const ll INFL = 3e18 + 100;

#define i128 __int128_t

struct _ {
    _() { cin.tie(0)->sync_with_stdio(0), cout.tie(0); }
} __;

template <typename T, T (*f)(T, T), T (*e)()> struct RBST {
    inline int rnd() {
        static int x = 123456789;
        static int y = 362436069;
        static int z = 521288629;
        static int w = 88675123;
        int t;

        t = x ^ (x << 11);
        x = y;
        y = z;
        z = w;
        return w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
    }
    struct node {
        node *l, *r;
        int cnt;
        T x, sum;
        node() = default;
        node(T x) : x(x), sum(x), l(0), r(0) { cnt = 1; }
    };
    RBST(int n) : pool(n) {}
    int cnt(const node *t) { return t ? t->cnt : 0; }
    T sum(const node *t) { return t ? t->sum : e(); }
    node *update(node *t) {
        t->cnt = cnt(t->l) + cnt(t->r) + 1;
        t->sum = f(f(sum(t->l), t->x), sum(t->r));
        return t;
    }
    vector<node> pool;
    int ptr = 0;
    inline node *alloc(const T &v) {
        if(si(pool) == ptr) pool.resize(si(pool) * 2);
        return &(pool[ptr++] = node(v));
    }
    node *merge(node *l, node *r) {
        if(!l or !r) return l ? l : r;
        if(rnd() % (cnt(l) + cnt(r)) < cnt(l)) {
            l->r = merge(l->r, r);
            return update(l);
        }
        r->l = merge(l, r->l);
        return update(r);
    }

    pair<node *, node *> split(node *t, int k) {
        if(!t) return {t, t};
        if(k <= cnt(t->l)) {
            auto [l, r] = split(t->l, k);
            t->l = r;
            return {l, update(t)};
        }
        auto [l, r] = split(t->r, k - cnt(t->l) - 1);
        t->r = l;
        return {update(t), r};
    }

    void insert(node *&t, int k, const T &v) {
        auto [l, r] = split(t, k);
        t = merge(merge(l, alloc(v)), r);
    }
};

int f(int x, int y) { return min(x, y); }
int e() { return INF; }

int main() {
    int n, q;
    cin >> n >> q;
    RBST<int, f, e> rbst(n + q);
    RBST<int, f, e>::node *root = nullptr;
    rep(i, n) {
        int x;
        cin >> x;
        rbst.insert(root, i, x);
    }

    rep(q) {
        int t;
        cin >> t;
        if(!t) {
            int l, r;
            cin >> l >> r;
            r++;
            auto [l1, tmp] = rbst.split(root, l);
            auto [mid, r1] = rbst.split(tmp, r - l);
            auto [m1, m2] = rbst.split(mid, rbst.cnt(mid) - 1);
            mid = rbst.merge(m2, m1);
            root = rbst.merge(rbst.merge(l1, mid), r1);
        } else if(t == 1) {
            int l, r;
            cin >> l >> r;
            r++;
            auto [l1, tmp] = rbst.split(root, l);
            auto [mid, r1] = rbst.split(tmp, r - l);
            cout << rbst.sum(mid) << '\n';
            root = rbst.merge(l1, rbst.merge(mid, r1));
        } else {
            int y, z;
            cin >> y >> z;
            auto [l1, tmp] = rbst.split(root, y);
            auto [mid, r1] = rbst.split(tmp, 1);
            mid = rbst.alloc(z);
            root = rbst.merge(rbst.merge(l1, mid), r1);
        }
    }
}
accuracy: 1
time_ms: 280
memory_kb: 15544
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;

//push から update を消している
template <class S, S (*op)(S, S), S (*e)(), class F, S (*mapping)(F, S), F (*composition)(F, F), F (*id)()>
struct Treap {
    private:
    unsigned int xorshift() {
        static unsigned int x = 123456789, y = 362436069, z = 521288629, w = 88675123;
        unsigned int t = (x ^ (x << 11));
        x = y;
        y = z;
        z = w;
        return (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)));
    }
    
    struct Node {
        Node *left, *right;
        S value;
        int priority, size;
        S sum;
        F lazy;
        int rev;
        
        Node(S value_, int priority_) : 
        left(nullptr), right(nullptr), value(value_), 
        priority(priority_), size(1),
        sum(value_), lazy(id()), rev(0) {}
    };
    
    Node *root = nullptr;
    
    int cnt(Node *t) {
        return t ? t->size : 0;
    }
    
    S get_sum(Node *t) {
        return t ? t->sum : e();
    }
    
    void update(Node *t) {
        if (t) {
            t->size = cnt(t->left) + cnt(t->right) + 1;
            t->sum = op(op(get_sum(t->left), t->value), get_sum(t->right));
        }
    }
    
    void push(Node *t) {
        if (t && t->rev) {
            t->rev = false;
            swap(t->left, t->right);
            if (t->left) {
                t->left->rev ^= 1;
            }
            if (t->right) {
                t->right->rev ^= 1;
            }
        }
        all_apply(t->left, t->lazy);
        all_apply(t->right, t->lazy);
        t->lazy = id();
        //update(t);
    }
    
    Node *merge(Node *lroot, Node *rroot) {
        if (!lroot || !rroot) {
            return lroot ? lroot : rroot;
        } else if (lroot->priority > rroot->priority) {
            push(lroot);
            lroot->right = merge(lroot->right, rroot);
            update(lroot);
            return lroot;
        } else {
            push(rroot);
            rroot->left = merge(lroot, rroot->left);
            update(rroot);
            return rroot;
        }
    }
    
    pair<Node *, Node *> split(Node *t, int k) {
        if (!t) {
            return {nullptr, nullptr};
        }
        push(t);
        if (k <= cnt(t->left)) {
            auto [lroot, rroot] = split(t->left, k);
            t->left = rroot;
            update(t);
            return {lroot, t};
        } else {
            auto [lroot, rroot] = split(t->right, k - cnt(t->left) - 1);
            t->right = lroot;
            update(t);
            return {t, rroot};
        }
    }
    
    void all_apply(Node *t, F f) {
        if (!t) {
            return;
        }
        t->value = mapping(f, t->value);
        t->sum = mapping(f, t->sum);
        t->lazy = composition(f, t->lazy);
    }
    
    void dump(Node *t) {
        if (!t) {
            return;
        }
        push(t);
        dump(t->left);
        cout << t->value << " ";
        dump(t->right);
    }
    
    public:
    Treap() {}
    Treap(vector<S> v) {
        std::reverse(v.begin(), v.end());
        for (S &x : v) {
            insert(0, x);
        }
    }
    
    void set(int p, S x) {
        erase(p);
        insert(p, x);
    }
    
    void insert(int p, S x) {
        auto [lroot, rroot] = split(root, p);
        root = merge(merge(lroot, new Node(x, xorshift())), rroot);
    }
    
    void erase(int p) {
        auto [Lroot, rroot] = split(root, p + 1);
        auto [lroot, mroot] = split(Lroot, p);
        root = merge(lroot, rroot);
    }
    
    S prod(int l, int r) {
        auto [Lroot, rroot] = split(root, r);
        auto [lroot, mroot] = split(Lroot, l);
        S res = mroot->sum;
        root = merge(merge(lroot, mroot), rroot);
        return res;
    }
    
    void apply(int l, int r, F f) {
        auto [Lroot, rroot] = split(root, r);
        auto [lroot, mroot] = split(Lroot, l);
        all_apply(mroot, f);
        root = merge(merge(lroot, mroot), rroot);
    }
    
    void reverse(int l, int r) {
        if (l > r) {
            return;
        }
        auto [Lroot, rroot] = split(root, r);
        auto [lroot, mroot] = split(Lroot, l);
        mroot->rev ^= 1;
        push(mroot);
        root = merge(merge(lroot, mroot), rroot);
    }
    
    void rotate(int l, int r, int m) {
        reverse(l, r);
        reverse(l, l + r - m);
        reverse(l + r - m, r);
    }
    
    S operator[](int p) {
        return prod(p, p + 1);
    }
    
    void dump() {
        dump(root);
        cout << endl;
    }
};

int op(int a, int b) {
    return min(a, b);
}

int e() {
    return 2000000000;
}

int mapping(int f, int x) {
    return f + x;
}

int composition(int f, int g) {
    return f + g;
}

int id() {
    return 0;
}

int main() {
    int n, q;
    cin >> n >> q;
    vector<int> a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    Treap<int, op, e, int, mapping, composition, id> tr(a);
    while (q--) {
        int t;
        cin >> t;
        if (t == 0) {
            int l, r;
            cin >> l >> r;
            tr.rotate(l, r + 1, r);
        } else if (t == 1) {
            int l, r;
            cin >> l >> r;
            cout << tr.prod(l, r + 1) << endl;
        } else {
            int p, x;
            cin >> p >> x;
            tr.set(p, x);
        }
    }
}
accuracy: 1
time_ms: 510
memory_kb: 16308
final_rank: 13