/* -*- coding: utf-8 -*- * * 749.cc: No.749 クエリ全部盛り - yukicoder */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; /* constant */ const int MAX_N = 1000000; const int MAX_E2 = 1 << 21; // = 2097152 const int D = 3; const int MOD = 1000000007; /* typedef */ typedef long long ll; typedef int vec[D]; typedef vec mat[D]; inline void initmat(mat a); inline void unitmat(mat a); inline void copymat(const mat a, mat b); inline void mulmat(const mat a, const mat b, mat c); inline void mulmatvec(const mat a, const vec b, vec c); template struct SegTreeFibo { int n, e2, ls[MAX_E2]; T as[MAX_E2], fs[MAX_E2]; bool dfs[MAX_E2]; mat ms[MAX_E2]; SegTreeFibo() {} void init(int _n) { n = _n; for (e2 = 1; e2 < n; e2 <<= 1); fs[e2 - 1 + 0] = 0, fs[e2 - 1 + 1] = 1; for (int i = 2, j = e2 - 1 + i; i < n; i++, j++) fs[j] = (fs[j - 1] + fs[j - 2]) % MOD; for (int i = 0; i < e2; i++) ls[e2 - 1 + i] = 1; for (int i = e2 - 2; i >= 0; i--) { int i1 = i * 2 + 1, i2 = i1 + 1; fs[i] = (fs[i1] + fs[i2]) % MOD; ls[i] = ls[i1] + ls[i2]; } for (int i = e2 - 2 + n; i >= 0; i--) unitmat(ms[i]); } T get(int i) { return as[e2 - 1 + i]; } void op_delegate(int k, int k1) { mat m1; vec v0, v1; v0[0] = as[k1], v0[1] = fs[k1], v0[2] = ls[k1]; mulmatvec(ms[k], v0, v1); as[k1] = v1[0]; mulmat(ms[k], ms[k1], m1); copymat(m1, ms[k1]); dfs[k1] = true; } void op_range(int r0, int r1, mat m, int k, int i0, int i1) { if (r1 <= i0 || i1 <= r0) return; mat m1; vec v0, v1; if (r0 <= i0 && i1 <= r1) { v0[0] = as[k], v0[1] = fs[k], v0[2] = ls[k]; mulmatvec(m, v0, v1); as[k] = v1[0]; mulmat(m, ms[k], m1); copymat(m1, ms[k]); dfs[k] = true; return; } int k1 = k * 2 + 1, k2 = k1 + 1; if (dfs[k]) { op_delegate(k, k1); op_delegate(k, k2); unitmat(ms[k]); dfs[k] = false; } int im = (i0 + i1) / 2; op_range(r0, r1, m, k1, i0, im); op_range(r0, r1, m, k2, im, i1); as[k] = (as[k1] + as[k2]) % MOD; } void op_range(int r0, int r1, mat m) { op_range(r0, r1, m, 0, 0, e2); } T sum_range(int r0, int r1, int k, int i0, int i1) { if (r1 <= i0 || i1 <= r0) return 0; if (r0 <= i0 && i1 <= r1) return as[k]; int k1 = k * 2 + 1, k2 = k1 + 1; if (dfs[k]) { op_delegate(k, k1); op_delegate(k, k2); unitmat(ms[k]); dfs[k] = false; } int im = (i0 + i1) / 2; T v0 = sum_range(r0, r1, k1, i0, im); T v1 = sum_range(r0, r1, k2, im, i1); return (v0 + v1) % MOD; } T sum_range(int r0, int r1) { return sum_range(r0, r1, 0, 0, e2); } }; /* global variables */ SegTreeFibo st; /* subroutines */ inline void initmat(mat a) { memset(a, 0, sizeof(mat)); } inline void unitmat(mat a) { initmat(a); for (int i = 0; i < D; i++) a[i][i] = 1; } inline void copymat(const mat a, mat b) { memcpy(b, a, sizeof(mat)); } inline void mulmat(const mat a, const mat b, mat c) { for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) { c[i][j] = 0; for (int k = 0; k < D; k++) c[i][j] = (c[i][j] + (ll)a[i][k] * b[k][j] % MOD) % MOD; } } inline void mulmatvec(const mat a, const vec b, vec c) { for (int i = 0; i < D; i++) { c[i] = 0; for (int j = 0; j < D; j++) c[i] = (c[i] + (ll)a[i][j] * b[j] % MOD) % MOD; } } /* main */ int main() { int n, qn; scanf("%d%d", &n, &qn); st.init(n); while (qn--) { int q, l, r, k; scanf("%d%d%d%d", &q, &l, &r, &k); r++; if (q == 0) { int sum = st.sum_range(l, r); printf("%lld\n", (ll)sum * k % MOD); } else { mat m; unitmat(m); switch (q) { // 1: ai = k case 1: m[0][0] = 0, m[0][2] = k; break; // 2: ai = ai + k case 2: m[0][2] = k; break; // 3: ai = ai * k case 3: m[0][0] = k; break; // 4: ai = ai + k * fi case 4: m[0][1] = k; break; } st.op_range(l, r, m); /* for (int i = 0; i < st.e2 - 1; i++) { int i1 = 2 * i + 1, i2 = i1 + 1; st.op_delegate(i, i1); st.op_delegate(i, i2); } for (int i = 0; i < st.e2 * 2 - 1; i++) printf("%d ", st.as[i]); putchar('\n'); */ } } return 0; }