#define NDEBUG
#include <cassert>
#include <cstddef>
#include <memory>
#include <stdexcept>
#include <utility>

template <class Semigroup> class splay_sequence {
public:
	using value_structure = Semigroup;
	using value_type = typename value_structure::value_type;
	using const_reference = const value_type &;
	using size_type = ::std::size_t;

private:
	class leaf_construct_t {};
	static constexpr leaf_construct_t leaf_construct{};
	class node_type {
		using pointer = ::std::unique_ptr<node_type>;
		using value_structure = typename splay_sequence::value_structure;
		using value_type = typename splay_sequence::value_type;
		using size_type = typename splay_sequence::size_type;

	public:
		pointer left, right;
		size_type size;
		value_type value;
		template <class... Args>
		node_type(typename splay_sequence::leaf_construct_t, Args &&... args)
			: left(), right(), size(1), value(::std::forward<Args>(args)...) {}
		node_type(pointer &&l, pointer &&r)
			: left(::std::move(l)), right(::std::move(r)),
			size(left->size + right->size),
			value(value_structure::operation(left->value, right->value)) {}
		void fix() {
			size = left->size + right->size;
			value = value_structure::operation(left->value, right->value);
		}
	};
	using pointer = ::std::unique_ptr<node_type>;

	static void splay(pointer &ptr, size_type index) {
		pointer left, right, temp;
		while (1) {
			if (index > ptr->left->size) {
				index -= ptr->left->size;
				temp = ::std::move(ptr->right);
				if (index > temp->left->size) {
					index -= temp->left->size;
					ptr->right = ::std::move(temp->left);
					ptr->fix();
					temp->left = ::std::move(ptr);
					ptr = ::std::move(temp->right);
					temp->right = ::std::move(left);
					left = ::std::move(temp);
				}
				else if (index < temp->left->size) {
					ptr->right = ::std::move(left);
					left = ::std::move(ptr);
					ptr = ::std::move(temp->left);
					temp->left = ::std::move(right);
					right = ::std::move(temp);
				}
				else {
					ptr->right = ::std::move(left);
					left = ::std::move(ptr);
					ptr = ::std::move(temp);
					break;
				}
			}
			else if (index < ptr->left->size) {
				temp = ::std::move(ptr->left);
				if (index > temp->left->size) {
					index -= temp->left->size;
					ptr->left = ::std::move(right);
					right = ::std::move(ptr);
					ptr = ::std::move(temp->right);
					temp->right = ::std::move(left);
					left = ::std::move(temp);
				}
				else if (index < temp->left->size) {
					ptr->left = ::std::move(temp->right);
					ptr->fix();
					temp->right = ::std::move(ptr);
					ptr = ::std::move(temp->left);
					temp->left = ::std::move(right);
					right = ::std::move(temp);
				}
				else {
					ptr->left = ::std::move(right);
					right = ::std::move(ptr);
					ptr = ::std::move(temp);
					break;
				}
			}
			else {
				break;
			}
		}
		while (left) {
			temp = ::std::move(left->right);
			left->right = ::std::move(ptr->left);
			left->fix();
			ptr->left = ::std::move(left);
			left = ::std::move(temp);
		}
		while (right) {
			temp = ::std::move(right->left);
			right->left = ::std::move(ptr->right);
			right->fix();
			ptr->right = ::std::move(right);
			right = ::std::move(temp);
		}
		ptr->fix();
	}

	pointer root;

	template <class... Args>
	void insert_in(const size_type index, Args &&... args) {
		if (!root) {
			root = ::std::make_unique<node_type>(leaf_construct,
				::std::forward<Args>(args)...);
		}
		else if (index == 0) {
			root = ::std::make_unique<node_type>(
				::std::make_unique<node_type>(leaf_construct,
					::std::forward<Args>(args)...),
				::std::move(root));
		}
		else if (index == size()) {
			root = ::std::make_unique<node_type>(
				::std::move(root),
				::std::make_unique<node_type>(leaf_construct,
					::std::forward<Args>(args)...));
		}
		else {
			splay(root, index);
			root->left = ::std::make_unique<node_type>(
				::std::move(root->left),
				::std::make_unique<node_type>(leaf_construct,
					::std::forward<Args>(args)...));
			root->fix();
		}
	}
	pointer erase_in(const size_type index) {
		pointer ret;
		if (size() == 1) {
			ret = ::std::move(root);
		}
		else if (index == 0) {
			splay(root, index + 1);
			ret = ::std::move(root->left);
			root = ::std::move(root->right);
		}
		else if (index + 1 == size()) {
			splay(root, index);
			ret = ::std::move(root->right);
			root = ::std::move(root->left);
		}
		else {
			splay(root, index + 1);
			splay(root->left, index);
			ret = ::std::move(root->left->right);
			root->left = ::std::move(root->left->left);
			root->fix();
		}
		return ::std::move(ret);
	}

	splay_sequence(pointer &&ptr) : root(::std::move(ptr)) {}

public:
	splay_sequence() : root() {}

	bool empty() const { return !root; }
	size_type size() const { return empty() ? 0 : root->size; }

	const_reference operator[](const size_type index) {
		assert(index < size());
		if (size() == 1) {
			return root->value;
		}
		else if (index == 0) {
			splay(root, index + 1);
			return root->left->value;
		}
		else if (index + 1 == size()) {
			splay(root, index);
			return root->right->value;
		}
		else {
			splay(root, index + 1);
			splay(root->left, index);
			return root->left->right->value;
		}
	}
	const_reference at(const size_type index) {
		if (index < size())
			return operator[](index);
		else
			throw ::std::out_of_range(
				"out of range : called `splay_sequence::at()` with invalid "
				"index");
	}
	const_reference front() {
		assert(!empty());
		return operator[](0);
	}
	const_reference back() {
		assert(!empty());
		return operator[](size() - 1);
	}
	const_reference fold(size_type first, size_type last) {
		assert(first < last);
		assert(last <= size());
		if (first == 0) {
			if (last == size()) {
				return root->value;
			}
			else {
				splay(root, last);
				return root->left->value;
			}
		}
		else {
			if (last == size()) {
				splay(root, first);
				return root->right->value;
			}
			else {
				splay(root, last);
				splay(root->left, first);
				return root->left->right->value;
			}
		}
	}

	void insert(const size_type index, const value_type &x) {
		assert(index <= size());
		insert_in(index, x);
	}
	void insert(const size_type index, value_type &&x) {
		assert(index <= size());
		insert_in(index, ::std::move(x));
	}
	template <class... Args>
	void emplace(const size_type index, Args &&... args) {
		assert(index <= size());
		insert_in(index, ::std::forward<Args>(args)...);
	}
	value_type erase(const size_type index) {
		assert(index < size());
		return ::std::move(erase_in(index)->value);
	}
	void push_back(const value_type &x) { insert_in(size(), x); }
	void push_back(value_type &&x) { insert_in(size(), ::std::move(x)); }
	void push_back(splay_sequence &&seq) {
		if (empty()) {
			root = ::std::move(seq.root);
		}
		else if (!seq.empty()) {
			root = ::std::make_unique<node_type>(::std::move(root),
				::std::move(seq.root));
		}
	}
	template <class... Args> void emplace_back(Args &&... args) {
		insert_in(size(), ::std::forward<Args>(args)...);
	}
	value_type pop_back() {
		assert(!empty());
		return ::std::move(erase_in(size() - 1)->value);
	}
	splay_sequence pop_back(const size_type position) {
		assert(position <= size());
		pointer temp;
		if (position == 0) {
			temp = ::std::move(root);
		}
		else if (position != size()) {
			splay(root, position);
			temp = ::std::move(root->right);
			root = ::std::move(root->left);
		}
		return splay_sequence(::std::move(temp));
	}
	void push_front(const value_type &x) { insert_in(0, x); }
	void push_front(value_type &&x) { insert_in(0, ::std::move(x)); }
	void push_front(splay_sequence &&seq) {
		if (empty) {
			root = ::std::move(seq.root);
		}
		else if (!seq.empty()) {
			root = ::std::make_unique<node_type>(::std::move(seq.root),
				::std::move(root));
		}
	}
	template <class... Args> void emplace_front(Args &&... args) {
		insert_in(0, ::std::forward<Args>(args)...);
	}
	value_type pop_front() {
		assert(!empty());
		return ::std::move(erase_in(0)->value);
	}
	splay_sequence pop_front(const size_type position) {
		assert(position <= size());
		pointer temp;
		if (position == size()) {
			temp = ::std::move(root);
		}
		else if (position != 0) {
			splay(root, position);
			temp = ::std::move(root->left);
			root = ::std::move(root->right);
		}
		return splay_sequence(::std::move(temp));
	}
};

#include <algorithm>
#include <limits>
template <class T> class min_monoid {
public:
	using value_type = T;
	static value_type operation(const value_type &x, const value_type &y) {
		return ::std::min(x, y);
	}
	static value_type identity() {
		return ::std::numeric_limits<value_type>::max();
	}
	static value_type reverse(const value_type &x) { return x; }
};

#include <cstdio>
using uint = unsigned int;
void scan(uint &d) {
	d = 0;
	int c;
	while (c = fgetc(stdin), c == ' ' || c == '\n');
	do d = d * 10 + c - '0'; while (c = fgetc(stdin), c != ' '&&c != '\n');
}

int main() {
	
	uint n, q, x, y, z;
	scan(n);
	scan(q);

	splay_sequence<min_monoid<uint>> ss;

	while (n--) {
		scan(x);
		ss.push_back(x);
	}

	while (q--) {
		scan(x);
		scan(y);
		scan(z);

		switch (x) {
		case 0: {
			ss.insert(y, ss.erase(z));
			break;
		}
		case 1: {
			printf("%u\n", ss.fold(y, z + 1));
			break;
		}
		case 2: {
			ss.erase(y);
			ss.insert(y, z);
			break;
		}
		}
	}

	return 0;
}



Measured memory_bytes: 23776