#include <bits/stdc++.h>;
using namespace std;
// Define the maximum size of the array and the modulo
const int MAXN = 1e5 + 5;
const int MOD = 1e9 + 7;
// Initialize the array, segment tree, and lazy propagation
// array
int n, m;
long long t[4 * MAXN], lazy[4 * MAXN];
// Function to build the segment tree
void build(int v, int tl, int tr)
{
// Initialize the lazy array with ones
lazy[v] = 1;
// If the segment has only one element
if (tl == tr) {
// Initialize the tree with the array
// values
t[v] = 1;
}
else {
// Calculate the middle of the segment
int tm = (tl + tr) / 2;
// Recursively build the left child
build(v * 2, tl, tm);
// Recursively build the right child
build(v * 2 + 1, tm + 1, tr);
// Merge the children values
t[v] = (t[v * 2] + t[v * 2 + 1]) % MOD;
}
}
// Function to propagate the lazy values to the children
void push(int v, int tl, int tr)
{
// Propagate the value
t[v] = (t[v] * lazy[v]) % MOD;
// If the node is not a leaf
if (tl != tr) {
// Update the lazy values for
// the left child
lazy[v * 2] = (lazy[v * 2] * lazy[v]) % MOD;
// Update the lazy values
// for the right child
lazy[v * 2 + 1] = (lazy[v * 2 + 1] * lazy[v]) % MOD;
}
// Reset the lazy value
lazy[v] = 1;
}
// Function to update a range of the array and the segment
// tree
void update(int v, int tl, int tr, int l, int r, int val)
{
// Apply the pending updates if any
push(v, tl, tr);
// If the range is invalid, return
if (l > r)
return;
// If the range matches the segment
if (l == tl && r == tr) {
// Update the lazy value
lazy[v] = (lazy[v] * val) % MOD;
// Apply the update immediately
push(v, tl, tr);
}
else {
// Calculate the middle of the segment
int tm = (tl + tr) / 2;
// Recursively update the left child
update(v * 2, tl, tm, l, min(r, tm), val);
// Recursively update the right child
update(v * 2 + 1, tm + 1, tr, max(l, tm + 1), r,
val);
// Merge the children values
t[v] = (t[v * 2] + t[v * 2 + 1]) % MOD;
}
}
// Function to query a range of the array
long long query(int v, int tl, int tr, int l, int r)
{
// Apply the pending updates if any
push(v, tl, tr);
// If the range is invalid, return 0
if (l > r)
return 0;
// If the range matches the segment
if (l <= tl && tr <= r) {
// Return the value of the segment
return t[v];
}
// Calculate the middle of the segment
int tm = (tl + tr) / 2;
// Return the sum of the queries on the
// children
return (query(v * 2, tl, tm, l, min(r, tm))
+ query(v * 2 + 1, tm + 1, tr, max(l, tm + 1),
r))
% MOD;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
// Input
vector<vector<int>> arr
= { { 1, 0, 3, 3 }, { 2, 1, 2 }, { 1, 1, 4, 4 },
{ 2, 1, 3 }, { 2, 1, 4 }, { 2, 3, 5 } };
// Number of elements in the array
n = 5;
// Number of operations
m = 6;
// Build the segment tree
build(1, 0, n - 1);
for (int i = 0; i < m; i++) {
// Type of the operation
int type = arr[i][0];
// If the operation is an update
if (type == 1) {
// Left boundary of the range
int l = arr[i][1];
// Right boundary of the range
int r = arr[i][2];
// Value to be multiplied
int val = arr[i][3];
// Update the range
update(1, 0, n - 1, l, r - 1, val);
}
// If the operation is a query
else {
// Left boundary of the range
int l = arr[i][1];
// Right boundary of the range
int r = arr[i][2];
// Print the result of the query
cout << query(1, 0, n - 1, l, r - 1) << "\n";
}
}
return 0;
}