#include <bits/stdc++.h>

using namespace std;

using int64 = long long;

// T: The type of values.
// U: The type of operators.
// Verified: AOJ-DSL2F
template<typename T, typename U>
class LazyPropagationSegmentTree {
 private:
  function<T(T, T)> merge;
  T empty_value;
  function<U(U, U)> op_merge;
  U empty_op;
  function<T(T, U)> apply_op;
  int num_nodes;  
  vector<T> nodes;
  vector<U> op_nodes;

  void DoLazyPropagation(int node_index) {
   if (op_nodes[node_index] != empty_op) {
      nodes[node_index] = apply_op(nodes[node_index], op_nodes[node_index]);
      if (node_index < num_nodes / 2) {
        op_nodes[2 * node_index] =
            op_merge(op_nodes[2 * node_index], op_nodes[node_index]);
        op_nodes[2 * node_index + 1] =
            op_merge(op_nodes[2 * node_index + 1], op_nodes[node_index]);
      }
      op_nodes[node_index] = empty_op;
    }
  }

  void ApplyOpRangeInternal(
      int node_index, int node_l, int node_r, int l, int r, U op) {
    DoLazyPropagation(node_index);

    if (node_r <= l || r <= node_l) return;

    if (l <= node_l && node_r <= r) {
      op_nodes[node_index] = op;
      DoLazyPropagation(node_index);
      return;
    }
    int node_m = (node_l + node_r) / 2;
    ApplyOpRangeInternal(2 * node_index, node_l, node_m, l, r, op);
    ApplyOpRangeInternal(2 * node_index + 1, node_m, node_r, l, r, op);
    nodes[node_index] = merge(nodes[2 * node_index], nodes[2 * node_index + 1]);
  }

  T GetRangeInternal(
      int node_index, int node_l, int node_r, int l, int r) {
    DoLazyPropagation(node_index);

    if (node_r <= l || r <= node_l) return empty_value;

    if (l <= node_l && node_r <= r) {
      return nodes[node_index];
    }

    int node_m = (node_l + node_r) / 2;
    return merge(
        GetRangeInternal(2 * node_index, node_l, node_m, l, r),
        GetRangeInternal(2 * node_index + 1, node_m, node_r, l, r));
  }

 public:
  LazyPropagationSegmentTree(
      function<T(T, T)> in_merge, T in_empty_value,
      function<U(U, U)> in_op_merge, U in_empty_op,
      function<T(T, U)> in_apply_op, vector<T> values) :
          merge(in_merge), empty_value(in_empty_value), op_merge(in_op_merge),
          empty_op(in_empty_op), apply_op(in_apply_op) {
    int n = values.size();
    num_nodes = 1;
    while (num_nodes < n) num_nodes *= 2;
    num_nodes *= 2;
    nodes = vector<T>(num_nodes, empty_value);
    op_nodes = vector<U>(num_nodes, empty_op);
    for (int i = 0; i < values.size(); ++i) {
      nodes[num_nodes / 2 + i] = values[i];
    }
    for (int i = num_nodes / 2 - 1; i >= 1; i--) {
      nodes[i] = merge(nodes[2 * i], nodes[2 * i + 1]);
    }
  }

  // Applies the operator to the range [l, r).
  void ApplyOpRange(int l, int r, U op) {
    return ApplyOpRangeInternal(1, 0, num_nodes / 2, l, r, op);
  }

  T GetRange(int l, int r) {
    return GetRangeInternal(1, 0, num_nodes / 2, l, r);
  }
};

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);

  int n, q;
  cin >> n >> q;
  vector<int> xs(n, 0);
  constexpr int EMPTY_OP = 0;

  auto merge =
      function<int(int, int)>([] (int x, int y) { return min(x, y); });
  auto op_merge =
      function<int(int, int)>([] (int x, int y) { return x + y; });
  auto apply_op =
      function<int(int, int)>([] (int x, int op) { return x + op; });
  auto tree = LazyPropagationSegmentTree<int, int>(
      merge, INT_MAX, op_merge, EMPTY_OP, apply_op, xs);

  for (int i = 0; i < q; i++) {
    int c;
    cin >> c;
    if (c == 0) {
      int s, t, v;
      cin >> s >> t >> v;
      tree.ApplyOpRange(s, t + 1, v);
      // tree.Dump();
    } else {
      int s, t;
      cin >> s >> t;
      cout << tree.GetRange(s, t + 1) << endl;
      // tree.Dump();
    }
  }
}


Measured memory_bytes: 5804