#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <memory>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#define FOR(i,a,b) for (int i=(a),for_##i##_max=(b);i<=(for_##i##_max);++i)
#define RFOR(i,a,b) for (int i=(a),rfor_##i##_min=(b);i>=(rfor_##i##_min);--i)
#define REP(i,n) for (int i=0,rep_##i##_len=(n);i<(rep_##i##_len);++i)
#define RREP(i,n) for (int i=(n)-1;i>=0;--i)

namespace { // Basics

template<typename T>
void chmin(T &x, T y) {
  x = std::min(x, y);
}

template<typename T>
void chmax(T &x, T y) {
  x = std::max(x, y);
}

template<typename T>
__attribute__((unused))
const auto minimum = static_cast<T const &(*)(T const &, T const &)>(std::min);

template<typename T>
__attribute__((unused))
const auto maximum = static_cast<T const &(*)(T const &, T const &)>(std::max);

template<typename T>
__attribute__((unused))
T constexpr infty = std::numeric_limits<T>::max / 3;
template<>
__attribute__((unused))
auto constexpr infty<int> = 1'100'100'100;
template<>
__attribute__((unused))
auto constexpr infty<long long int> = 100'500'400'300'200'100LL;

using lli = long long int;
using ld = long double;

} // namespace

namespace  { // Implicit Treap

template <typename T, typename FnT, typename Serv>
class itreap {
  public:
    struct node_t {
      using ptr_t = std::unique_ptr<node_t>;
      T key; double prio; ptr_t lc, rc; size_t cnt; T sum;
      explicit node_t(T v, double p): key(v), prio(p), lc(), rc(), cnt(1), sum(v) {}
      static size_t count(node_t *t) { return t? t->cnt : 0; }
      static size_t total(node_t *t, T unit) { return t? t->sum : unit; }
      T at(size_t idx) const {
        auto const ls = count(lc.get());
        if (idx == ls) { return key; }
        return (idx < ls)? lc->at(idx) : rc->at(idx - ls - 1);
      }
      void recompute(FnT const &append, T unit) {
        cnt = count(lc.get()) + 1 + count(rc.get());
        auto const lv = total(lc.get(), unit);
        auto const rv = total(rc.get(), unit);
        sum = append(lv, append(key, rv));
      }
      static std::pair<ptr_t, ptr_t> split(ptr_t t, size_t k, FnT const &app, T unit) {
        if (!t) { return std::make_pair(nullptr, nullptr); }
        if (k <= count(t->lc.get())) {
          auto s = split(std::move(t->lc), k, app, unit);
          t->lc = std::move(s.second); t->recompute(app, unit);
          return std::make_pair(std::move(s.first), std::move(t));
        } else {
          auto s = split(std::move(t->rc), k - count(t->lc.get()) - 1, app, unit);
          t->rc = std::move(s.first); t->recompute(app, unit);
          return std::make_pair(std::move(t), std::move(s.second));
        }
      }
      static ptr_t merge(ptr_t l, ptr_t r, FnT const &app, T unit) {
        if (!l || !r) { return std::move(l? l : r); }
        if (l->prio > r->prio) {
          l->rc = merge(std::move(l->rc), std::move(r), app, unit);
          l->recompute(app, unit);
          return l;
        } else {
          r->lc = merge(std::move(l), std::move(r->lc), app, unit);
          r->recompute(app, unit);
          return r;
        }
      }
    };
    using ptr_t = typename node_t::ptr_t;

    explicit itreap(std::shared_ptr<Serv> s, size_t N, T v): srv(s), root() {
      for (size_t i = 0; i < N; ++i) {
        push_back(v);
      }
    }
    explicit itreap(std::shared_ptr<Serv> s, ptr_t &&r): srv(s), root(std::move(r)) {}
    T const operator[] (size_t idx) const {
      return root->at(idx);
    }
    void update(size_t idx, T v) {
      auto right = eliminate(idx+1);
      eliminate(idx);
      push_back(v);
      merge(std::move(right));
    }
    void merge(itreap &&right) {
      root = node_t::merge(std::move(root), std::move(right.root), srv->get_op(), srv->get_unit());
    }
    void push_back(T v) {
      auto const p = srv->generate_priority();
      root = node_t::merge(std::move(root), std::make_unique<node_t>(v, p),
          srv->get_op(), srv->get_unit());
    }
    itreap eliminate(size_t N) {
      auto s = node_t::split(std::move(root), N, srv->get_op(), srv->get_unit());
      root = std::move(s.first);
      return itreap(srv, std::move(s.second));
    }
    void insert(size_t idx, T v) {
      auto const right = eliminate(idx);
      push_back(v);
      merge(std::move(right));
    }
    void erase(size_t idx) {
      auto right = eliminate(idx);
      merge(right.eliminate(1));
    }
    T query(size_t first, size_t last) {
      if (first == last) { return 0; }
      auto right = eliminate(last);
      auto mid = eliminate(first);
      T ans = mid.root->sum;
      merge(std::move(mid));
      merge(std::move(right));
      return ans;
    }
  private:
    std::shared_ptr<Serv> srv;
    ptr_t root;
};

template <typename T, typename FnT>
class itreap_server: public std::enable_shared_from_this<itreap_server<T, FnT>> {
  public:
    using Seq = itreap<T, FnT, itreap_server>;
    static std::shared_ptr<itreap_server> create(FnT fn, T e) {
      return std::make_shared<itreap_server>(fn, e);
    }
    explicit itreap_server(FnT fn, T e):
      mt(std::random_device()()), dis(0, 1), append(fn), unit(e) { }
    Seq make_seq(size_t N, T v) {
      return Seq(this->shared_from_this(), N, v);
    }
    double generate_priority() {
      return dis(mt);
    }
    FnT const &get_op() const { return append; }
    T get_unit() const { return unit; }
  private:
    std::mt19937 mt;
    std::uniform_real_distribution<double> dis;
    FnT append;
    T unit;
};

} // namespace

using namespace std;

using Serv = itreap_server<lli, lli const &(*)(lli const &, lli const &)>;

int main() {
  int N, Q; cin >> N >> Q;
  auto srv = Serv::create(static_cast<lli const &(*)(lli const &, lli const &)>(std::min), infty<lli>);
  auto seq = srv->make_seq(N+10, 0);

  REP(i, N) {
    int A; cin >> A;
    seq.update(i, A);
  }
  REP(query, Q) {
    int X; cin >> X;
    if (X == 0) {
      int L, R; cin >> L >> R;
      auto d = seq.eliminate(R+1);
      auto c = seq.eliminate(R);
      auto b = seq.eliminate(L);
      seq.merge(std::move(c));
      seq.merge(std::move(b));
      seq.merge(std::move(d));
    } else if (X == 1) {
      int L, R; cin >> L >> R;
      cout << seq.query(L, R+1) << endl;
    } else {
      int P, V; cin >> P >> V;
      seq.update(P, V);
    }
  }
}



Measured memory_bytes: 15748