#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) { }
    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;
    }
}

// void show(avl_node *p, int d = 0) {
//     if (p) {
//         show(p->left, d + 1);
//         cout << string(d*2, ' ');
//         cout << "(" << p->key << ", " << p->min << ")" << endl;
//         show(p->right, d + 1);
//     }
// }

// np merge_into_left(np t1, np par, np t2) {
//     if (height(t1) > height(t2) + 1) {
//         t1->right = merge_into_left(t1->right, par, t2);
//         update(t1);
//         return balance(t1);
//     } else {
//         par->left = t1;
//         par->right = t2;
//         update(par);
//         assert(abs(bfactor(par)) < 2);
//         return par;
//     }
// }

// np merge_into_right(np t1, np par, np t2) {
//     if (height(t1) + 1 < height(t2)) {
//         t2->left = merge_into_right(t1, par, t2->left);
//         update(t2);
//         return balance(t2);
//     } else {
//         par->left = t1;
//         par->right = t2;
//         update(par);
//         assert(abs(bfactor(par)) < 2);
//         return par;
//     }
// }

// np merge(np t1, np t2) {
//     if (t1 == nullptr) return t2;
//     if (t2 == nullptr) return t1;
//     if (size(t1) > size(t2)) {
//         np x = find_leftmost(t2);
//         t2 = remove_leftmost(t2);
//         return merge_into_left(t1, x, t2);
//     } else {
//         np x = find_rightmost(t1);
//         t1 = remove_rightmost(t1);
//         return merge_into_right(t1, x, t2);
//     }
// }

// np merge(np t1, np par, np t2) {
//     assert(size(par) == 1);
//     if (size(t1) > size(t2)) {
//         return merge_into_left(t1, par, t2);
//     } else {
//         return merge_into_right(t1, par, t2);
//     }
// }

// pair<np, np> split_at(np t, int k) {
//     assert(0 <= k && k <= size(t));
//     if (t == nullptr) return { nullptr, nullptr };
//     np l = t->left, r = t->right;
//     t->left = t->right = nullptr;
//     update(t);
//     int sl = size(l);
//     if (k < sl) {
//         np ll, lr;
//         tie(ll, lr) = split_at(l, k);
//         r = merge(lr, t, r);
//         return {ll, r};
//     } else if (k == sl) {
//         r = merge(t, r);
//         return {l, r};
//     } else {
//         np rl, rr;
//         tie(rl, rr) = split_at(r, k - sl - 1);
//         l = merge(l, t, rl);
//         return {l, rr};
//     }
// }

// pair<np, np> split(np t, int x) {
//     if (t == nullptr) return { nullptr, nullptr };
//     np l = t->left, r = t->right;
//     t->left = t->right = nullptr;
//     update(t);
//     if (x < t->key) {
//         np ll, lr;
//         tie(ll, lr) = split(l, x);
//         r = merge(lr, t, r);
//         return {ll, r};
//     } else if (x == t->key) {
//         r = merge(t, r);
//         return {l, r};
//     } else {
//         np rl, rr;
//         tie(rl, rr) = split(r, x);
//         l = merge(l, t, rl);
//         return {l, rr};
//     }
// }

// namespace test {
//     void test(np n) {
//         if (n) {
//             assert(bfactor(n) < 2);
//             if (n->left) assert(n->left->key < n->key);
//             if (n->right) assert(n->key < n->right->key);
//             assert(n->size = size(n->left) + size(n->right) + 1);
//             assert(n->height = 1 + max(size(n->left), size(n->right)));
//             test(n->left);
//             test(n->right);
//         }
//     }

//     void to_array(np n, vector<int> &a) {
//         if (n) {
//             to_array(n->left, a);
//             a.push_back(n->key);
//             to_array(n->right, a);
//         }
//     }

//     // void test_merge() {
//     //     rep(i, 100000) {
//     //         int n = rand() % 10;
//     //         int m = rand() % 10;
//     //         vector<int> a;
//     //         {
//     //             set<int> s;
//     //             while ((int)s.size() < n + m) {
//     //                 s.insert(rand() % 1000);
//     //             }
//     //             for (auto &x : s) {
//     //                 a.push_back(x);
//     //             }
//     //         }
//     //         np t1 = nullptr;
//     //         rep(i, n) t1 = insert(t1, a[i]);
//     //         np t2 = nullptr;
//     //         rep(i, m) t2 = insert(t2, a[n + i]);
//     //         np t = merge(t1, t2);
//     //         vector<int> na;
//     //         to_array(t, na);
//     //         assert(a == na);
//     //     }
//     // }

//     // void test_split_at() {
//     //     rep(i, 100000) {
//     //         if (i % 100) dump(i);
//     //         int n = rand() % 100;
//     //         vector<int> a;
//     //         {
//     //             set<int> s;
//     //             while ((int)s.size() < n) {
//     //                 s.insert(rand() % 1000);
//     //             }
//     //             for (auto &x : s) {
//     //                 a.push_back(x);
//     //             }
//     //         }
//     //         np t = nullptr;
//     //         rep(i, n) t = insert(t, a[i]);
//     //         int k = rand() % (n + 1);
//     //         np l, r;
//     //         tie(l, r) = split_at(t, k);
//     //         vector<int> na;
//     //         to_array(l, na);
//     //         assert((int)na.size() == k);
//     //         to_array(r, na);
//     //         assert((int)na.size() == n);
//     //         assert(a == na);
//     //     }
//     // }
// }

// np insert_ms(np n, int x) {
//     np l, r;
//     tie(l, r) = split(n, x);
//     return merge(l, new avl_node(x), r);
// }

// np remove_at_ms(np n, int k) {
//     np l, r;
//     tie(l, r) = split_at(n, k);
//     np rr = remove_leftmost(r);
//     return merge(l, rr);
// }

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: 19500