//================================= // Created on: 2018/10/19 22:08:20 //================================= #include #define show(x) std::cerr << #x << " = " << x << std::endl using ll = long long; using ull = unsigned long long; using ld = long double; constexpr ll MOD = 1000000007LL; template constexpr T INF = std::numeric_limits::max() / 10; std::mt19937 mt{std::random_device{}()}; constexpr std::size_t PC(ull v) { return v = (v & 0x5555555555555555ULL) + (v >> 1 & 0x5555555555555555ULL), v = (v & 0x3333333333333333ULL) + (v >> 2 & 0x3333333333333333ULL), v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL, static_cast(v * 0x0101010101010101ULL >> 56 & 0x7f); } constexpr std::size_t LG(ull v) { return v == 0 ? 0 : (v--, v |= (v >> 1), v |= (v >> 2), v |= (v >> 4), v |= (v >> 8), v |= (v >> 16), v |= (v >> 32), PC(v)); } constexpr ull SZ(const ull v) { return 1ULL << LG(v); } template class LazySegmentTree { public: using BaseAlgebra = Base; using AccMonoid = typename BaseAlgebra::AccMonoid; using OpMonoid = typename BaseAlgebra::OpMonoid; using T = typename BaseAlgebra::T; using F = typename BaseAlgebra::OpMonoid::T; LazySegmentTree(const std::size_t n) : data_num(n), half(SZ(n)), value(half << 1, AccMonoid::id()), action(half << 1, OpMonoid::id()) {} template LazySegmentTree(const InIt first, const InIt last) : data_num(distance(first, last)), half(SZ(data_num)), value(half << 1, AccMonoid::id()), action(half << 1, OpMonoid::id()) { copy(first, last, value.begin() + half); for (std::size_t i = half - 1; i >= 1; i--) { up(i); } } T get(const std::size_t a) const { return accumulate(a, a + 1); } void set(std::size_t a, const T& val) { modify(a, a + 1, OpMonoid::id()), value[a += half] = val; while (a >>= 1) { up(a); } } T accumulate(const std::size_t L, const std::size_t R) const { auto arec = [&](auto&& self, const std::size_t index, const std::size_t left, const std::size_t right) -> T { if (L <= left and right <= R) { return value[index]; } else if (right <= L or R <= left) { return AccMonoid::id(); } else { return act(action[index], acc(self(self, index << 1, left, (left + right) >> 1), self(self, index << 1 | 1, (left + right) >> 1, right))); } }; return arec(arec, 1, 0, half); } void modify(const std::size_t L, const std::size_t R, const F& f) { auto mrec = [&](auto&& self, const std::size_t index, const std::size_t left, const std::size_t right) -> void { if (L <= left and right <= R) { this->down(index, f); } else if (right <= L or R <= left) { // Do nothing } else { this->down(index << 1, action[index]), this->down(index << 1 | 1, action[index]); self(self, index << 1, left, (left + right) >> 1), self(self, index << 1 | 1, (left + right) >> 1, right); this->up(index), action[index] = OpMonoid::id(); } }; mrec(mrec, 1, 0, half); } //private: void up(const std::size_t i) { value[i] = acc(value[i << 1], value[i << 1 | 1]); } void down(const std::size_t i, const F& f) { value[i] = act(f, value[i]), action[i] = compose(f, action[i]); } const std::size_t data_num, half; std::vector value; // Tree for value(length: size) std::vector action; // Tree for action(length: half) const AccMonoid acc{}; const OpMonoid compose{}; const BaseAlgebra act{}; }; template std::ostream& operator<<(std::ostream& os, const LazySegmentTree& seg) { os << "["; for (std::size_t i = 0; i < seg.data_num; i++) { os << seg.get(i) << ","; } return (os << "]" << std::endl); } std::vector sum(1000000); struct MAct { static ll fib(const int l, const int r) { return (sum[r - 1] + MOD - (l == 0 ? 0 : sum[l - 1])) % MOD; } struct T { int l, r; ll sum; }; struct AccMonoid { T operator()(const T& a, const T& b) const { return T{std::min(a.l, b.l), std::max(a.r, b.r), (a.sum + b.sum) % MOD}; } static T id() { return T{INF, -INF, 0}; } }; struct OpMonoid { struct T { ll modify; ll add; ll mul; ll fibo; }; T operator()(const T& f1, const T& f2) const { if (f1.modify != INF) { return T{f1.modify, 0, 1, f1.fibo}; } else { if (f2.modify != INF) { const ll mod = (f2.modify * f1.mul % MOD + f1.add) % MOD; const ll fibo = (f2.fibo * f1.mul % MOD + f1.fibo) % MOD; return T{mod, 0, 1, fibo}; } else { const ll mul = f1.mul * f2.mul % MOD; const ll add = (f1.mul * f2.add % MOD + f1.add) % MOD; const ll fibo = (f1.mul * f2.fibo % MOD + f1.fibo) % MOD; return T{INF, add, mul, fibo}; } } } static T id() { return T{INF, 0, 1, 0}; } }; T operator()(const OpMonoid::T& f, const T& x) const { const int l = x.l, r = x.r; if (l == INF or r == -INF) { return x; } ll sum = x.sum; if (f.modify != INF) { sum = (r - l) * f.modify % MOD; } (sum *= f.mul) %= MOD; (sum += f.add * (r - l) % MOD) %= MOD; (sum += f.fibo * fib(l, r) % MOD) %= MOD; return T{l, r, sum}; } }; std::ostream& operator<<(std::ostream& os, const MAct::T& v) { return (os << "(" << v.l << "," << v.r << ");" << v.sum); } int main() { std::cin.tie(0); std::ios::sync_with_stdio(false); int N, Q; std::cin >> N >> Q; sum[0] = 0, sum[1] = 1; using T = MAct::T; using F = MAct::OpMonoid::T; std::vector v(N, MAct::AccMonoid::id()); for (int i = 0; i < N; i++) { v[i] = T{i, i + 1, 0}; } LazySegmentTree seg(v.begin(), v.end()); for (int i = 2; i < N; i++) { sum[i] = (sum[i - 1] + sum[i - 2]) % MOD; } for (int i = 1; i < N; i++) { (sum[i] += sum[i - 1]) %= MOD; } for (int q = 0; q < Q; q++) { int t, l, r; ll k; std::cin >> t >> l >> r >> k, r++; if (t == 0) { const T acc = seg.accumulate(l, r); std::cerr << acc.l << " " << acc.r << " " << acc.sum << std::endl; std::cout << acc.sum * k % MOD << "\n"; } else if (t == 1) { seg.modify(l, r, F{k, 0, 1, 0}); } else if (t == 2) { seg.modify(l, r, F{INF, k, 1, 0}); } else if (t == 3) { seg.modify(l, r, F{INF, 0, k, 0}); } else { seg.modify(l, r, F{INF, 0, 1, k}); } // show(seg); } return 0; }