#define NDEBUG 1
#include <set>
#include <tuple>
#include <vector>
#include <iostream>
#include <cassert>
#include <algorithm>
#include <sstream>
using namespace std;
using ll = long long;
#define FOR(i, a, b) for (int i = (a); i < int(b); ++i)
#define RFOR(i, a, b) for (int i = (b)-1; i >= int(a); --i)
#define rep(i, n) FOR(i, 0, n)
#define rep1(i, n) FOR(i, 1, int(n) + 1)
#define rrep(i, n) RFOR(i, 0, n)
#define rrep1(i, n) RFOR(i, 1, int(n) + 1)
#define all(c) begin(c), end(c)
const int MOD = 1000000007;

const int INF = 1e9;

template <typename T>
void __dump__(std::ostream &os, const T &first) {
    os << first;
}
template <typename First, typename... Rest>
void __dump__(std::ostream &os, const First &first, const Rest &... rest) {
    os << first << ", ";
    __dump__(os, rest...);
}
#define dump(...)                                         \
    do {                                                  \
        std::ostringstream os;                            \
        os << __LINE__ << ":\t" << #__VA_ARGS__ << " = "; \
        __dump__(os, __VA_ARGS__);                        \
        std::cerr << os.str() << std::endl;               \
    } while (0)

struct avl_node {
    int key;
    avl_node* left;
    avl_node* right;
    int height;
    int size;
    int min;
    avl_node() { }
    avl_node(int k) : key(k), left(nullptr), right(nullptr), height(1), size(1), min(k) { }
    avl_node(int k, avl_node *l, avl_node *r, int h, int s, int m) : key(k), left(l), right(r), height(h), size(s), min(m) { }
    void *operator new (size_t) {
        static avl_node pool[400010];
        static avl_node *p = pool;
        return p++;
    }
};

using np = avl_node*;

int height(avl_node* p) {
    return p != nullptr ? p->height : 0;
}

int size(np p) {
    return p != nullptr ? p->size : 0;
}

int minimum(np p) {
    return p != nullptr ? p->min : INF;
}

int bfactor(np p) {
    return height(p->right) - height(p->left);
}

np update(np p) {
    p->height = max(height(p->left), height(p->right)) + 1;
    p->size = size(p->left) + size(p->right) + 1;
    p->min = std::min({minimum(p->left), minimum(p->right), p->key});
    return p;
}

np rotate_right(np p) {
    np q = p->left;
    p->left = q->right;
    q->right = p;
    update(p);
    update(q);
    return q;
}

np rotate_left(np q) {
    np p = q->right;
    q->right = p->left;
    p->left = q;
    update(q);
    update(p);
    return p;
}

np balance(np p) {
    int bf = bfactor(p);
    if (bf == 2) {
        if (bfactor(p->right) < 0) p->right = rotate_right(p->right);
        return rotate_left(p);
    }
    if (bf == -2) {
        if (bfactor(p->left) > 0) p->left = rotate_left(p->left);
        return rotate_right(p);
    }
    assert(abs(bfactor(p)) < 2);
    return p;
}

np insert(np p, int x) {
    if (p == nullptr) return new avl_node(x);
    if (x < p->key) p->left = insert(p->left, x);
    else p->right = insert(p->right, x);
    return balance(update(p));
}

np insert_at(np p, int k, int x) {
    if (p == nullptr) return new avl_node(x);
    int sl = size(p->left);
    if (k <= sl) p->left = insert_at(p->left, k, x);
    else p->right = insert_at(p->right, k - sl - 1, x);
    return balance(update(p));
}

np find_leftmost(np p) {
    return p->left != nullptr ? find_leftmost(p->left) : p;
}

np find_rightmost(np p) {
    return p->right != nullptr ? find_rightmost(p->right) : p;
}

np remove_leftmost(np p) {
    if (p->left == nullptr) return p->right;
    p->left = remove_leftmost(p->left);
    update(p);
    return balance(p);
}

np remove_rightmost(np p) {
    if (p->right == nullptr) return p->left;
    p->right = remove_rightmost(p->right);
    update(p);
    return balance(p);
}

np remove(np n, int k) {
    if (n == nullptr) return nullptr;
    if (k < n->key) n->left = remove(n->left, k);
    else if (k > n->key) n->right = remove(n->right, k);
    else {
        np l = n->left;
        np r = n->right;
        //delete n;
        if (r == nullptr) return l;
        np min = find_leftmost(r);
        min->right = remove_leftmost(r);
        min->left = l;
        update(n);
        return balance(update(min));
    }
    update(n);
    return balance(n);
}

np remove_at(np n, int k) {
    if (n == nullptr) return nullptr;
    int sl = size(n->left);
    if (k < sl) n->left = remove_at(n->left, k);
    else if (sl < k) n->right = remove_at(n->right, k - sl - 1);
    else {
        np l = n->left;
        np r = n->right;
        if (r == nullptr) return l;
        np min = find_leftmost(r);
        min->right = remove_leftmost(r);
        min->left = l;
        return balance(update(min));
    }
    update(n);
    return balance(n);
}

int at(np n, int k) {
    if (n == nullptr) return -1;
    int ls = size(n->left);
    if (k < ls) {
        return at(n->left, k);
    } else if (ls == k) {
        return n->key;
    } else {
        return at(n->right, k - ls - 1);
    }
}

void upd(np n, int k, int x) {
    int sl = size(n->left);
    if (k < sl) {
        upd(n->left, k, x);
    } else if (k == sl) {
        n->key = x;
    } else {
        upd(n->right, k - sl - 1, x);
    }
    update(n);
}

int rmq(np n, int l, int r) {
    if (l == 0 && r == n->size) {
        return n->min;
    } else {
        int sl = size(n->left);
        int res = INF;
        if (l < sl) {
            res = min(res, rmq(n->left, l, min(r, sl)));
        }
        if (l <= sl && sl < r) {
            res = min(res, n->key);
        }
        if (sl + 1 < r) {
            res = min(res, rmq(n->right, max(0, l - sl - 1), r - sl - 1));
        }
        return res;
    }
}

np build(int *l, int *r) {
    int n = r - l;
    if (n <= 0) return nullptr;
    int *m = l + n / 2;
    np res = new avl_node(*m);
    res->left = build(l, m);
    res->right = build(m + 1, r);
    return update(res);
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(0);
    int n, q;
    while (cin >> n >> q) {
        static int a[200010];
        rep(i,n) cin >> a[i];
        np root = build(a, a + n);
        // show(root);
        rep(i, q){
            int op;
            cin >> op;
            if(false){
            } else if(op == 0){
                int l, r;
                cin >> l >> r;
                int tmp = at(root, r);
                root = remove_at(root, r);
                // dump(l, r, tmp);
                // cout << "=== removed" << endl;
                // show(root);
                // cout << "===" << endl;
                root = insert_at(root, l, tmp);
            } else if(op == 1){
                int l, r;
                cin >> l >> r;
                cout << rmq(root, l, r + 1) << '\n';
            } else if(op == 2){
                int p, v;
                cin >> p >> v;
                upd(root, p, v);
            }
            // cout << "=== show" << endl;
            // show(root);
            // cout << "===" << endl;
        }
    }
}

Measured memory_bytes: 19544