import scala.util.Random

object Main extends App {

  import scala.io.StdIn._
  import Tree._

  val Array(n, q) = readLine.trim.split(' ').map(_.toInt)
  val elements = List.tabulate(n){_ ⇒ readLine.trim.toInt}
  val tree = treeOf(elements:_*)
  for (_ ← 0 until q){
    val Array(x, y, z) = readLine.trim.split(' ').map(_.toInt)
    x match {
      case 0 ⇒
        val value = tree.find(z)
        tree.erase(z)
        tree.insert(y, value)
      case 1 ⇒
        println(tree.min(y, z))
      case 2 ⇒
        tree.erase(y)
        tree.insert(y, z)
    }
    //println(tree.toList.mkString(" "))
  }
  implicit class ScopeFunc[T](val value: T) {
    def let[A](func: T ⇒ A): A = func(value)

    def also(func: T ⇒ Unit): T = {
      func(value)
      value
    }
  }
}
package object Tree{
  private val rand: Random = new Random(1)
  def treeOf(elements: Int*): Tree = {
    val tree = new TreeImpl()
    for ((v,i) ← elements.zipWithIndex) {
      tree.insert(i, v)
    }
    tree
  }
  sealed trait Tree{
    def size: Int
    def insert(rank: Int, value: Int): Unit
    def erase(rank: Int): Unit
    def find(rank: Int): Int
    def min(from: Int, to: Int): Int
    def toList: List[Int]
  }
  private class TreeImpl(var tree: Option[Tree] = None) extends Tree{
    override def size: Int = tree.map(_.size).getOrElse(0)

    override def insert(rank: Int, value: Int): Unit = {
      tree match {
        case None ⇒ tree = Some(new Node(0.5, value, None, None))
        case Some(t) ⇒ t.insert(rank, value)
      }
    }

    override def erase(rank: Int): Unit = {
      tree match {
        case Some(t) if t.size == 1 ⇒ tree = None
        case Some(t) ⇒ t.erase(rank)
      }
    }

    override def find(rank: Int): Int = tree.map(_.find(rank)).get

    override def min(from: Int, to: Int): Int = tree.map(_.min(from, to)).get

    override def toList: List[Int] = tree.map(_.toList).getOrElse(Nil)
  }
  private class Node(var priority: Double, var value: Int, var left: Option[Node], var right: Option[Node]) extends Tree{
    var size: Int = List(left, right).flatMap{_.map(_.size)}.sum + 1
    var min: Int = math.min(value, List(left, right).flatMap(_.map(_.min)).fold(Int.MaxValue){case (a, b) ⇒ if (a > b) b else a})
    private def _renewMin: Unit = {
      min = math.min(value, List(left, right).flatMap(_.map(_.min)).fold(Int.MaxValue){case (a, b) ⇒ if (a > b) b else a})
    }
    private def _isLeaf: Boolean = size == 1
    private def _insert(rank: Int, value: Int, priority: Double): Unit = {
      size += 1
      (left, right) match {
        case (None, None) ⇒ rank match {
          case 0 ⇒
            if (priority > this.priority) {
              right = Some(new Node(this.priority, this.value, None, None))
              this.priority = priority
              this.value = value
            } else {
              left = Some(new Node(priority, value, None, None))
            }
          case 1 ⇒
            if (priority > this.priority){
              left = Some(new Node(this.priority, this.value, None, None))
              this.priority = priority
              this.value = value
            }else{
              right = Some(new Node(priority, value, None, None))
            }
        }
        case (Some(l), None) ⇒
          if (l.size >= rank) {
            l._insert(rank, value, priority)
            if (priority > this.priority) {
              right = Some(new Node(this.priority, this.value, l.right, right))
              this.priority = l.priority
              this.value = l.value
              left = l.left
            }
          } else {
            if (priority > this.priority){
              left = Some(new Node(this.priority, this.value, left, right))
              this.priority = priority
              this.value = value
            }else {
              right = Some(new Node(priority, value, None, None))
            }
          }
        case (None, Some(r)) ⇒
          if (rank == 0){
            if (priority > this.priority){
              right = Some(new Node(this.priority, this.value, left, right))
              this.priority = priority
              this.value = value
            }else {
              left = Some(new Node(priority, value, None, None))
            }
          }else {
            r._insert(rank - 1, value, priority)
            if (priority > this.priority) {
              left = Some(new Node(this.priority, this.value, left, r.left))
              this.priority = priority
              this.value = value
              right = r.right
            }
          }
        case (Some(l), Some(r)) ⇒
          if (l.size >= rank){
            l._insert(rank, value, priority)
            if (priority > this.priority){
              right = Some(new Node(this.priority, this.value, l.right, right))
              this.priority = priority
              this.value = value
              left = l.left
            }
          } else {
            r._insert(rank - l.size - 1, value, priority)
            if (priority > this.priority){
              left = Some(new Node(this.priority, this.value, left, r.left))
              this.priority = priority
              this.value = value
              right = r.right
            }
          }
      }
      _renewMin
    }

    override def toString: String = toList.mkString(" ")
    private def _erase(rank: Int): Unit = {
      //println(s"rank = $rank, left = (${left.map(_.toString).getOrElse("")}) current = $value right = ${right.map(_.toString).getOrElse("")}")
      size -= 1
      (left, right) match {
        case (Some(l), Some(r)) ⇒ {
          l.size.compare(rank) match {
            case 1 ⇒ {
              if (l._isLeaf) {
                left = None
              } else {
                l._erase(rank)
              }
            }
            case -1 ⇒ {
              if (r._isLeaf){
                right = None
              }else {
                r._erase(rank - l.size - 1)
              }
            }
            case 0 ⇒ {
              if (l.priority > r.priority) {
                right = Some(new Node(this.priority, this.value, l.right, right))
                this.priority = l.priority
                this.value = l.value
                left = l.left
                right.foreach(_._erase(rank - l.left.map(_.size).getOrElse(0) - 1))
              } else {
                left = Some(new Node(this.priority, this.value, left, r.left))
                this.priority = r.priority
                this.value = r.value
                right = r.right
                left.foreach(_._erase(rank))
              }
            }
          }
        }
        case (Some(l), None) ⇒ {
          l.size.compare(rank) match {
            case 0 ⇒ {
              this.priority = l.priority
              this.value = l.value
              left = l.left
              right = l.right
            }
            case 1 ⇒ {
              if (l._isLeaf) {
                left = None
              }else{
                l._erase(rank)
              }
            }
          }
          _renewMin
        }
        case (None, Some(r)) ⇒ {
          0.compare(rank) match {
            case 0 ⇒ {
              this.priority = r.priority
              this.value = r.value
              left = r.left
              right = r.right
            }
            case -1 ⇒ {
              if (r._isLeaf){
                right = None
              }else{
                r._erase(rank - 1)
              }
            }
          }
        }
      }
    }
    private def _find(rank: Int): Int = {
      (left, right) match {
        case (Some(l), Some(r)) ⇒ {
          l.size.compare(rank) match {
            case 0 ⇒ value
            case -1 ⇒ r._find(rank - l.size - 1)
            case 1 ⇒ l._find(rank)
          }
        }
        case (Some(l), None) ⇒ {
          l.size.compare(rank) match {
            case 0 ⇒ value
            case 1 ⇒ l._find(rank)
          }
        }
        case (None, Some(r)) ⇒ {
          0.compare(rank) match {
            case 0 ⇒ value
            case -1 ⇒ r._find(rank - 1)
          }
        }
        case (None, None) ⇒ value
      }
    }
    private def _min(from: Int, to: Int): Int = {
      if (from <= 0 && to >= size - 1) min
      else if (from >= size || to < 0) Int.MaxValue
      else {
        (left, right) match {
          case (Some(l), Some(r)) ⇒
            List(l._min(from, to), r._min(from - l.size - 1, to - l.size - 1), if ((from to to).contains(l.size)) value else Int.MaxValue).min
          case (Some(l), None) ⇒
            List(l._min(from, to), if ((from to to).contains(l.size)) value else Int.MaxValue).min
          case (None, Some(r)) ⇒
            List(r._min(from - 1, to - 1), if ((from to to).contains(0)) value else Int.MaxValue).min
          case (None, None) ⇒ value
        }
      }
    }

    private def _toList(list: List[Int]): List[Int] = {
      (left, right) match {
        case (Some(l), Some(r)) ⇒ l._toList(value::r._toList(list))
        case (Some(l), None) ⇒ l._toList(value::list)
        case (None, Some(r)) ⇒ value::r._toList(list)
        case (None, None) ⇒ value::list
      }
    }

    override def insert(rank: Int, value: Int): Unit = {
      require((0 to size).contains(rank))
      assert(List(left, right).flatMap(_.map(_.size)).sum + 1 == size)
      val priority = rand.nextDouble()
      _insert(rank, value, priority)
    }
    override def erase(rank: Int): Unit = {
      require((0 to size).contains(rank))
      assert(List(left, right).flatMap(_.map(_.size)).sum + 1 == size)
      _erase(rank)
    }
    def find(rank: Int): Int = {
      require((0 until size).contains(rank))
      _find(rank)
    }

    override def min(from: Int, to: Int): Int = {
      require((0 until size).contains(from) && (0 until size).contains(to) && from <= to)
      _min(from, to)
    }

    override def toList: List[Int] = {
      _toList(Nil)
    }
  }

}
