#include <bits/stdc++.h>
//#ifdef CHECK_


template<typename T>
T get() { return 0; }
template<>
int get() { int x; scanf("%d", &x); return x; }
template<>
long get() { long x; scanf("%ld", &x); return x; }

template<typename T>
void put(T x) {}
template<>
void put(int x) { printf("%d\n", x); }
template<>
void put(long x) { printf("%ld\n", x); }
template<>
void put(std::string str) { printf("%s\n", str.c_str()); }
template<>
void put(const char* str) { printf("%s\n", str); }


class Node {
public:
  Node *left, *right;
  int num;
  int value;
  int min;
  Node() {}
};

class NodeHeap {
public:
  std::vector<Node*> xss;
  int n;
  NodeHeap() : n(262144) {}
  Node* next() {
    if( n == 262144 ) {
      n = 0;
      Node *p = new Node[262144];
      xss.push_back(p);
    }
    return &xss[xss.size()-1][n++];
  }
};
NodeHeap nheap;

inline Node* initLeaf(int v) {
  //Node *res = new Node;
  Node *res = nheap.next();
  res->left = res->right = nullptr;
  res->num = 1;
  res->value = v;
  res->min = v;
  return res;
}

inline Node* initNode(Node* base, Node* left, Node* right) {
#ifdef Persistent
  //Node *res = new Node;
  Node *res = nheap.next();
#else
  Node *res = base != nullptr ? base : nheap.next();
#endif
  res->left = left;
  res->right = right;
  res->num = 0;
  res->value = 0;
  res->min = (1 << 30);
  return res;
}

inline bool isLeaf(Node* p) {
  if( p == nullptr ) return false;
  return p->left == nullptr and p->right == nullptr;
}

inline int getNum(Node* p) {
  if( p == nullptr ) return 0;
  if( isLeaf(p) ) return 1;
  return p->num;
}

inline Node* getLeft(Node* p) {
  if( p == nullptr ) return nullptr;
  return p->left;
}

inline Node* getRight(Node* p) {
  if( p == nullptr ) return nullptr;
  return p->right;
}

inline int getValue(Node* p) {
  if( p == nullptr ) return (1 << 30);
  return p->value;
}

inline int getMin(Node* p) {
  if( p == nullptr ) return (1 << 30);
  return p->min;
}

// checker
void dump2(Node* node) {
  if( node == nullptr ) return;
  if( node->left == nullptr and node->right == nullptr ) {
    printf("{%d,%d}", node->value, node->min);
    return;
  }
  printf("(%d,%d)[", node->num, node->min);
  dump2(node->left);
  putchar(',');
  dump2(node->right);
  putchar(']');
}

Node* dump(Node* node) {
  dump2(node);
  putchar('\n');
  return node;
}

int maxDepth(Node* node) {
  if( node == nullptr ) return -1;
  if( isLeaf(node) ) return 0;
  return 1 + std::max(maxDepth(getLeft(node)), maxDepth(getRight(node)));
}

inline Node* update(Node* p) {
  if( p == nullptr ) return nullptr;
  assert( not isLeaf(p) );
  p->num = getNum(getLeft(p)) + getNum(getRight(p));
  p->min = std::min(getMin(getLeft(p)), getMin(getRight(p)));
  return p;
}

Node* merge(Node* left, Node* right) {
  if( left == nullptr and right == nullptr ) return nullptr;
  if( isLeaf(left) and isLeaf(right) ) return update(initNode(nullptr, left, right));
  if( left == nullptr ) {
    if( isLeaf(right) ) {
      return right;
    }
    else {
      return update(initNode(right, getLeft(right), getRight(right)));
    }
  }
  if( right == nullptr ) {
    if( isLeaf(left) ) {
      return left;
    }
    else {
      return update(initNode(left, getLeft(left), getRight(left)));
    }
  }
  if( getNum(left) < getNum(right) or (getNum(left) == getNum(right) and rand() % 2 == 0) ) {
    if( isLeaf(right) ) return update(initNode(nullptr, left, right));
    // left merged
    Node *w = merge(left, getLeft(right));
    Node *v = initNode(right, w, getRight(right));
    if( isLeaf(w) or w == nullptr ) return update(v);
    //rotate right only
    //right
    if( getNum(getLeft(w)) - getNum(getRight(v)) > 0 ) {
      v->left  = getRight(w);
      w->right = v;
      update(v);
      return update(w);
    }
    if( getNum(getLeft(getRight(w))) + getNum(getRight(getRight(w))) - getNum(getRight(v)) > 0 ) {
      Node *ml = getLeft(getRight(w));
      Node *mr = getRight(getRight(w));
      Node *x = initNode(w->right, w, v);
      w->right = ml;
      v->left  = mr;
      update(w);
      update(v);
      return update(x);
    }
    return update(v);
  }
  else {
    if( isLeaf(left) ) return update(initNode(nullptr, left, right));
    Node *w = merge(getRight(left), right);
    Node *v = initNode(left, getLeft(left), w);
    if( isLeaf(w) or w == nullptr ) return update(v);
    // rotate left only
    // left
    if( getNum(getRight(w)) - getNum(getLeft(v)) > 0 ) {
      v->right = getLeft(w);
      w->left  = v;
      update(v);
      return update(w);
    }
    if( getNum(getLeft(getLeft(w))) + getNum(getRight(getLeft(w))) - getNum(getLeft(v)) > 0 ) {
      Node *ml = getLeft(getLeft(w));
      Node *mr = getRight(getLeft(w));
      Node *x = initNode(getLeft(w), v, w);
      v->right = ml;
      w->left  = mr;
      update(v);
      update(w);
      return update(x);
    }
    return update(v);
  }
}

// [0, k), [k, size)
std::pair<Node*, Node*> split(Node* p, int k) {
  if( getNum(p) == k ) return std::pair<Node*, Node*>(p, nullptr);
  if( k == 0 ) return std::pair<Node*, Node*>(nullptr, p);
  if( k <= getNum(getLeft(p)) ) {
    Node *left, *right;
    std::tie(left, right) = split(getLeft(p), k);
    return std::pair<Node*, Node*>(left, merge(right, getRight(p)));
  }
  else {
    Node *left, *right;
    std::tie(left, right) = split(getRight(p), k - getNum(getLeft(p)));
    return std::pair<Node*, Node*>(merge(getLeft(p), left), right);
  }
}

// [l, r)
int minimum(Node* p, int l, int r) {
  if( isLeaf(p) ) return p->value;
  if( l == 0 and r == getNum(p) ) return p->min;
  if( r <= getNum(getLeft(p)) ) {
    return minimum(getLeft(p), l, r);
  }
  else if( getNum(getLeft(p)) <= l ) {
    return minimum(getRight(p), l - getNum(getLeft(p)), r - getNum(getLeft(p)));
  }
  else {
    int leftmin  = minimum(getLeft(p), l, getNum(getLeft(p)));
    int rightmin = minimum(getRight(p), 0, r - getNum(getLeft(p)));
    return std::min(leftmin, rightmin);
  }
}


int main() {
  Node *root = nullptr;
  int n = get<int>();
  int q = get<int>();
  for(int i = 0; i < n; ++i) {
    int a = get<int>();
    root = merge(root, initLeaf(a));
    //dump(root);
  }
  for(int i = 0; i < q; ++i) {
    const int x = get<int>();
    int y = get<int>();
    int z = get<int>();
    if( x == 0 ) {
      Node *nl, *nr;
      std::tie(nl, nr) = split(root, z + 1);
      Node *nll, *nlr;
      std::tie(nll, nlr) = split(nl, z);
      Node *nlll, *nllr;
      std::tie(nlll, nllr) = split(nll, y);
      root = merge(merge(merge(nlll, nlr), nllr), nr);      
    }
    if( x == 1 ) {
      int res = minimum(root, y, z + 1);
      printf("%d\n", res);
    }
    if( x == 2 ) {
      Node *nl, *nr;
      std::tie(nl, nr) = split(root, y + 1);
      Node *nll, *nlr;
      std::tie(nll, nlr) = split(nl, y);
      root = merge(merge(nll, initLeaf(z)), nr);
    }
    //dump(root);
  }
  // int t = getNum(root);
  // root = merge(root, root);
  // dump(root);
  // root = split(root, t).first;
  // dump(root);
  // for(int i = 0; i < 17; ++i) {
  //   root = merge(root, root);
  // }
  // printf("numnode  : %d\n", getNum(root));
  // printf("maxdepth : %d\n", maxDepth(root));
  
  return 0;
}

//#else

// template<typename T>
// T get() { return 0; }
// template<>
// int get() { int x; scanf("%d", &x); return x; }
// template<>
// long get() { long x; scanf("%ld", &x); return x; }

// template<typename T>
// void put(T x) {}
// template<>
// void put(int x) { printf("%d\n", x); }
// template<>
// void put(long x) { printf("%ld\n", x); }
// template<>
// void put(std::string str) { printf("%s\n", str.c_str()); }
// template<>
// void put(const char* str) { printf("%s\n", str); }

//#define CHECK_
//#include __FILE__
//#endif

Measured memory_bytes: 229352