#include <bits/stdc++.h>

template<typename T>
class treap_seq{
    using value_type = T;
    using size_type = size_t;

    class node_t {
    public:
        value_type value, query;
        size_type priority, size;
        node_t *left, *right;

        constexpr node_t(value_type _value, size_type _priority) : value(_value), query(_value), priority(_priority), size(1), left(
                nullptr), right(nullptr) {}

        constexpr value_type operator*() noexcept { return value; }

        constexpr size_type get_priority() noexcept { return priority; }

        constexpr value_type operator[](size_type k) {
            auto t = left ? left -> size : 0;
            return t < k ? (*right)[k - t - 1] : (t > k ? (*left)[k] : this -> value);
        }

        constexpr node_t *lower_bound(value_type v) {
            if (value == v)return this;
            if (value < v) {
                if (!left)return left;
                return left->lower_bound(v);
            } else {
                if (!right)return this;
                return right->lower_bound(v);
            }
        }

        constexpr size_t lower_size(value_type v) {
            if(value == v)return left ? left -> size : 0;
            if(value < v)return (left ? left -> size : 0) + 1 + (right ? right -> lower_size(v) : 0);
            return (left ? left -> lower_size(v) : 0);
        }

        void print(size_t n, std::ostream& os){
            if(right)right -> print(n + 5, os);
            for(size_t i = 0; i < n; ++i)os << " ";
            os << "(" << value << ", " << query << ", " << (priority >> 32) << ")" << std::endl;
            if(left)left -> print(n + 5, os);
        }
    };

    node_t* root;

    node_t* update(node_t* node){
        node -> size = 1;
        node -> query = node -> value;
        if(node -> left){
            node -> size += node -> left -> size;
            node -> query = std::min(node -> query, node -> left -> query);
        }
        if(node -> right){
            node -> size += node -> right -> size;
            node -> query = std::min(node -> query, node -> right -> query);
        }
        return node;
    }

    size_t sze(node_t* node) {
        return node ? node -> size : 0;
    }

    node_t* merge(node_t* left, node_t* right){
        /*if(left)left -> print(0);
        else puts("v");
        if(right)right -> print(0);
        else puts("v");
        puts("");*/
        if(!left)return right;
        if(!right)return left;

        if(left -> get_priority() > right -> get_priority()){
            left -> right = merge(left -> right, right);
            return update(left);
        }else{
            right -> left = merge(left, right -> left);
            return update(right);
        }
    }

    std::pair<node_t*, node_t*> split(node_t* root, size_t nth){
        if(!root)return {nullptr, nullptr};

        if(nth <= sze(root -> left)){
            auto s = split(root -> left, nth);
            root -> left = s.second;
            return {s.first, update(root)};
        }else{
            auto s = split(root -> right, nth - 1 - sze(root -> left));
            root -> right = s.first;
            return {update(root), s.second};
        }
    }

public:

    explicit treap_seq(value_type _v, size_type _p) : root(new node_t(_v, _p)) {}

    treap_seq() : root(nullptr) {}

    void insert(T value, size_t priority, size_type ichi){
        if(root){
            auto *nw = new node_t(value, priority);
            auto t = split(root, ichi);
            root = merge(merge(t.first, nw), t.second);
        }else{
            root = new node_t(value, priority);
        }
    }

    void erase(/*value_type value, */size_type k){
        //auto k = root -> lower_size(value);
        auto t1 = split(root, k);
        auto t2 = split(t1.second, 1);
        root = merge(t1.first, t2.second);
    }

    void shift(size_type l, size_type r){
        auto t = split(root, r);
        auto k = split(t.first, r - 1);
        auto s = split(k.first, l);
        root = merge(merge(s.first, k.second), merge(s.second, t.second));
    }

    value_type query(size_type l, size_type r){
        auto t1 = split(root, r);
        auto t2 = split(t1.first, l);
        auto ret = t2.second -> query;
        root = merge(merge(t2.first, t2.second), t1.second);
        return ret;
    }

    constexpr value_type operator[](size_type k) {
        return (*root)[k];
    }

    void print(std::ostream& os = std::cout){
        if(root)root -> print(0, os);
    }
};

int main(){
    using namespace std;
    size_t n, q;
    cin >> n >> q;
    random_device rdv{};
    mt19937_64 mt(rdv());
    treap_seq<size_t> tp;
    for(unsigned long i = 0, a; i < n; ++i){
        cin >> a;
        tp.insert(a, mt(), i);
    }
    //tp.print(cerr);
    for(unsigned long i = 0, x, y, z; i < q; ++i){
        cin >> x >> y >> z;
        if(x == 0){
            tp.shift(y, z + 1);
        }else if(x == 1){
            cout << tp.query(y, z + 1) << endl;
        }else{
            tp.erase(y);
            tp.insert(z, mt(), y);
        }
    }
    return 0;
}


Measured memory_bytes: 19872