Problem: Given n numbers a0, a1, ..., an-1 and q.
I want you to perform appropriate processing for q queries.
The query has the following three types of operations.


* Shift the value
Given a pair of l and r. (l <r) Circular shift the value from al to ar.

0 1 2 3 4 5 6 7 8 9

Is given the query l = 2, r = 5.

The shifted number sequence is

0 1 5 2 3 4 6 7 8 9

Will be.


* Find the minimum value
Given a pair of l and r. (l ≤ r)
Find the smallest value from al to ar.


* Update value
Given a pair of pos and val. Update the value of apos to val.



Input

The input is given in the following format.


n q
a0
a1
..
..
..
an-1
x1 y1 z1
x2 y2 z2
..
..
..
xq yq zq


If xi = 0, it represents a shift query. At this time, let l = yi and r = zi.
If xi = 1, it represents a query for the minimum value. At this time, let l = yi and r = zi.
If xi = 2, it represents a query that updates the value. At this time, pos = yi, val = zi.


Input meets the following constraints
1 ≤ n, q ≤ 200,000
0 ≤ ai ≤ 10,000,000 For queries that update values, 0 ≤ val ≤ 10,000,000

Output

When xi = 1 is given as a query, output the value of the answer on one line.

Examples

Input

10 3
0
1
2
3
4
5
6
7
8
9
1 5 7
0 2 5
1 5 7


Output

5
4


Input

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


Output

238335
238335
238335
368690

Solution (in CPP):

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

using T = int;
const T id = INT_MAX;
T op(T l, T r) {
	return min(l, r);
}

using COL = bool;
const COL RED = false, BLACK = true;

struct node {
	COL color;
	int size;
	int level;
	T val, all;
	node *p, *ch[2];
	node() : color(BLACK), size(0), level(0), val(id), all(id), p(nullptr), ch{ nullptr, nullptr } {}
	node(COL c, T v, node *par, node *l, node *r) : color(c), size(1), level(0), val(v), all(v), p(par), ch{ l, r } {}
};

node* const NIL = new node();

node* new_node(T val) {
	return new node(RED, val, NIL, NIL, NIL);
}
void update(node *x) {
	x->size = x->ch[0]->size + 1 + x->ch[1]->size;
	x->level = x->ch[0]->level + (x->color == BLACK);
	x->all = op(op(x->ch[0]->all, x->val), x->ch[1]->all);
}
void update(node *root, node *x) {
	while (x != NIL) update(x), x = x->p;
}
void rotate(node *&root, node *x, int b) {
	node *y = x->ch[1 - b];
	x->ch[1 - b] = y->ch[b];
	if (y->ch[b] != NIL) {
		y->ch[b]->p = x;
	}
	y->p = x->p;
	if (x->p == NIL) {
		root = y;
	}
	else {
		x->p->ch[x != x->p->ch[0]] = y;
	}
	y->ch[b] = x;
	x->p = y;
	update(x);
	update(y);
}
void insert_fix(node *&root, node *x) {
	while (x->p->color == RED) {
		int b = (x->p != x->p->p->ch[0]);
		node *y = x->p->p->ch[1 - b];
		if (y->color == RED) {
			x->p->color = BLACK;
			y->color = BLACK;
			x->p->p->color = RED;
			x = x->p->p;
			continue;
		}
		if (x == x->p->ch[1 - b]) {
			x = x->p;
			rotate(root, x, b);
		}
		x->p->color = BLACK;
		x->p->p->color = RED;
		rotate(root, x->p->p, 1 - b);
	}
	root->color = BLACK;
}
void transplant(node *&root, node *u, node *v) {
	if (u->p == NIL) {
		root = v;
	}
	else {
		u->p->ch[u != u->p->ch[0]] = v;
	}
	v->p = u->p;
}
void erase_fix(node *&root, node *x) {
	while (x != root && x->color == BLACK) {
		int b = (x != x->p->ch[0]);
		node *w = x->p->ch[1 - b];
		if (w->color == RED) {
			w->color = BLACK;
			x->p->color = RED;
			rotate(root, x->p, b);
			w = x->p->ch[1 - b];
		}
		if (w->ch[b]->color == BLACK && w->ch[1 - b]->color == BLACK) {
			w->color = RED;
			x = x->p;
			continue;
		}
		if (w->ch[1 - b]->color == BLACK) {
			w->ch[b]->color = BLACK;
			w->color = RED;
			rotate(root, w, 1 - b);
			w = x->p->ch[1 - b];
		}
		w->color = x->p->color;
		x->p->color = BLACK;
		w->ch[1 - b]->color = BLACK;
		rotate(root, x->p, b);
		x = root;
	}
	x->color = BLACK;
}
node* find_first(node *x) {
	if (x == NIL) return NIL;
	while (x->ch[0] != NIL) x = x->ch[0];
	return x;
}
node* find(node *&root, int k) {
	if (k < 0 || root->size <= k) return NIL;
	node *x = root;
	while (x->ch[0]->size != k) {
		if (k < x->ch[0]->size) {
			x = x->ch[0];
		}
		else {
			k -= x->ch[0]->size + 1;
			x = x->ch[1];
		}
	}
	return x;
}
void insert(node *&root, int k, T val) {
	node *y = NIL, *v = new_node(val);
	if (root == NIL) {
		root = v;
	}
	else if (k == 0) {
		y = find_first(root);
		y->ch[0] = v;
	}
	else {
		y = find(root, k - 1);
		if (y->ch[1] == NIL) {
			y->ch[1] = v;
		}
		else {
			y = find_first(y->ch[1]);
			y->ch[0] = v;
		}
	}
	v->p = y;
	update(root, y);
	insert_fix(root, v);
}
void erase(node *&root, node *x) {
	if (x == NIL) return;
	node *y = x, *z;
	COL c = y->color;
	if (x->ch[0] == NIL) {
		z = x->ch[1];
		transplant(root, x, x->ch[1]);
	}
	else if (x->ch[1] == NIL) {
		z = x->ch[0];
		transplant(root, x, x->ch[0]);
	}
	else {
		y = find_first(x->ch[1]);
		c = y->color;
		z = y->ch[1];
		if (y->p == x) {
			z->p = y;
		}
		else {
			transplant(root, y, y->ch[1]);
			y->ch[1] = x->ch[1];
			y->ch[1]->p = y;
		}
		transplant(root, x, y);
		y->ch[0] = x->ch[0];
		y->ch[0]->p = y;
		y->color = x->color;
		update(y);
	}
	update(root, z->p);
	if (c == BLACK) {
		erase_fix(root, z);
	}
}
void erase(node *&root, int k) {
	node *x = find(root, k);
	erase(root, x);
}
T find(node *t, int l, int r) {
	if (t == NIL || r <= 0 || t->size <= l) return id;
	if (l <= 0 && t->size <= r) return t->all;
	int c = t->ch[0]->size;
	return op(op(find(t->ch[0], l, r), l <= c && c < r ? t->val : id), find(t->ch[1], l - (c + 1), r - (c + 1)));
}

int main()
{
	ios::sync_with_stdio(false), cin.tie(0);
	int n, q, x, y, z, a;
	cin >> n >> q;
	node *root = NIL;
	for (int i = 0; i < n; i++) {
		cin >> a;
		insert(root, i, a);
	}
	while (q--) {
		cin >> x >> y >> z;
		if (x == 0) {
			node* t = find(root, z);
			int val = t->val;
			erase(root, t);
			insert(root, y, val);
		}
		else if (x == 1) {
			printf("%d\n", find(root, y, z + 1));
		}
		else {
			node *t = find(root, y);
			t->val = z;
			update(root, t);
		}
	}
	return 0;
}