#include <cstdio>
#include <set>
using namespace std;
const long long MOD_VALUE = 1000000007LL;
long long simple_sum_a[500002];
int just_b[500002];
int next_index_b_non_one[500002];
int next_index_a_non_zero[500002];
int agg_a[500002];
int agg_b[500002];
int n;
int q;
int a;
int b;
int last_index_b_non_one;
int last_index_a_non_zero;
int x;
int l;
int r;
long long current_value;
int current_round;
long long inverse_mod(long long value) {
int exp = MOD_VALUE - 2;
long long res = 1LL;
long long base = value;
while (exp > 0) {
if (exp % 2 == 1) {
res = (res * base) % MOD_VALUE;
}
base = (base * base) % MOD_VALUE;
exp = exp / 2;
}
return res;
}
int main() {
// read n & q
scanf("%d %d", &n, &q);
// read and precompute values (a, b)
last_index_b_non_one = 0;
last_index_a_non_zero = 0;
simple_sum_a[0] = 0;
just_b[0] = 1;
agg_a[0] = 0;
agg_b[0] = 1;
for (int i = 1; i <= n; i++) {
scanf("%d %d", &a, &b);
// store b
just_b[i] = b;
// sum values a
simple_sum_a[i] = simple_sum_a[i - 1] + (long long)a;
// set next index where b > 1
if (b > 1) {
for (int j = last_index_b_non_one; j < i; j++) {
next_index_b_non_one[j] = i;
}
last_index_b_non_one = i;
}
// set next index where a > 0
if (a > 0) {
for (int j = last_index_a_non_zero; j < i; j++) {
next_index_a_non_zero[j] = i;
}
last_index_a_non_zero = i;
}
// aggregate parts a (additions) and b (multiplications), modulo 1000000007
if (b == 1) { // increase a part only (choose addition), if multiplier b == 1
agg_a[i] = (agg_a[i - 1] + a) % MOD_VALUE;
} else {
agg_a[i] = ((long long)agg_a[i - 1] * (long long)b) % MOD_VALUE;
}
agg_b[i] = ((long long)agg_b[i - 1] * (long long)b) % MOD_VALUE;
}
// set -1 for next index tables, to the end
for (int j = last_index_b_non_one; j <= n; j++) {
next_index_b_non_one[j] = -1;
}
for (int j = last_index_a_non_zero; j <= n; j++) {
next_index_a_non_zero[j] = -1;
}
// printf("=== START - ARRAYS DUMP ===\n");
// printf("[i], just_b, simple_sum_a, next b>1, next a>0, agg_a, agg_b\n");
// for (int i = 0; i <= n; i++) {
// printf("[%d] %d %lld %d %d %d %d\n", i, just_b[i], simple_sum_a[i], next_index_b_non_one[i], next_index_a_non_zero[i], agg_a[i], agg_b[i]);
// }
// printf("=== END - ARRAYS DUMP ===\n");
// process requests
for (int i = 0; i < q; i++) {
scanf("%d %d %d", &x, &l, &r);
current_value = x;
current_round = l;
// printf("=== PROCESSING REQUEST %d ===\n", i);
// special case for initial value == 0 - find first non zero a
if (current_value == 0) {
current_round = next_index_a_non_zero[current_round];
if ((current_round == -1) || (current_round > r)) { // no non zero a util the end (or, at least, until round r is reached)
current_round = r;
// printf("NO NON ZERO A UNTIL THE EXPECTED ROUND (OR UNTILE THE END AT ALL)!!!\n");
}
current_value = simple_sum_a[current_round] - simple_sum_a[current_round - 1];
// printf("A ZERO SPECIAL CASE, curr_round=%d, curr_value=%lld\n", current_round, current_value);
}
// process kind of step by step, until surpass mod value
while (current_round < r) {
// add accumulated values a first (may be no-op in fact, if we have b>1 index after index, but it should result in adding 0)
int temp_next_index_b_non_one = next_index_b_non_one[current_round];
if ((temp_next_index_b_non_one == -1) || (temp_next_index_b_non_one > r)) { // no b>1 until the end at all or until the end of expected round
temp_next_index_b_non_one = r + 1; // a bit hacky, but it needs to point to the next value after the last expected round, to include the expected one
}
long long temp_diff = simple_sum_a[temp_next_index_b_non_one - 1] - simple_sum_a[current_round];
current_value = current_value + temp_diff;
current_round = temp_next_index_b_non_one - 1; // minus 1, because that round is not processed yet after this step
// printf("ADDING AGGREGATED SIMPLE SUM A DIFF; next_b_non_one=%d, diff=%lld, curr_round=%d, curr_value=%lld\n", temp_next_index_b_non_one, temp_diff, current_round, current_value);
// if crossed mod value, break the loop now
if (current_value >= MOD_VALUE) {
current_value = current_value % MOD_VALUE;
// printf("CROSSED MOD VALUE (A), BREAKING THE LOOP, curr_value=%lld, curr_round=%d\n", current_value, current_round);
break;
}
// if reached the expected round, also break the loop
if (current_round >= r) {
// printf("REACHED EXPETED ROUND AFTER STEP A, curr_value=%lld, curr_round=%d\n", current_value, current_round);
break;
}
// apply mutliplier b OR add a - depending what is better
current_round = current_round + 1;
long long temp_a = simple_sum_a[current_round] - simple_sum_a[current_round - 1]; // get value a back from sums
long long temp_sum = current_value + temp_a;
long long temp_multiply = current_value * (long long)just_b[current_round];
if (temp_sum > temp_multiply) {
current_value = temp_sum;
// printf("APPLIED ADDITION A, sum=%lld, multi=%lld, a=%lld, b=%d, curr_round=%d, curr_value=%lld\n", temp_sum, temp_multiply, temp_a, just_b[current_round], current_round, current_value);
} else {
current_value = temp_multiply;
// printf("APPLIED MULTIPLY B, sum=%lld, multi=%lld, a=%lld, b=%d, curr_round=%d, curr_value=%lld\n", temp_sum, temp_multiply, temp_a, just_b[current_round], current_round, current_value);
}
// if crossed mod value, break the loop now
if (current_value >= MOD_VALUE) {
current_value = current_value % MOD_VALUE;
// printf("CROSSED MOD VALUE (B), BREAKING THE LOOP, curr_value=%lld, curr_round=%d\n", current_value, current_round);
break;
}
}
// if current_round not achieved, it means that previous loop was broken (so we passed the mod value)
if (current_round < r) {
// so we need to apply "difference" multiplification of b (r "minus" current round), using inverse mod, and add diff of a (r "minus" current round)
long long temp_b_r = agg_b[r];
long long temp_a_r = agg_a[r];
long long temp_b_curr = agg_b[current_round];
long long temp_a_curr = agg_a[current_round];
long long temp_b_curr_inv_mod = inverse_mod(temp_b_curr);
long long temp_b_diff = (temp_b_r * temp_b_curr_inv_mod) % MOD_VALUE;
long long temp_a_diff = ((temp_a_r - temp_a_curr * temp_b_diff) % MOD_VALUE + MOD_VALUE) % MOD_VALUE;
current_value = (current_value * temp_b_diff + temp_a_diff) % MOD_VALUE;
// printf("APPLIED DIFFS, b_r=%lld, a_r=%lld, b_curr=%lld, a_curr=%lld, b_curr_inv_mod=%lld, b_diff=%lld, a_diff=%lld, current_value=%lld\n", temp_b_r, temp_a_r, temp_b_curr, temp_a_curr, temp_b_curr_inv_mod, temp_b_diff, temp_a_diff, current_value);
}
// print value
printf("%lld\n", current_value);
}
return 0;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | #include <cstdio> #include <set> using namespace std; const long long MOD_VALUE = 1000000007LL; long long simple_sum_a[500002]; int just_b[500002]; int next_index_b_non_one[500002]; int next_index_a_non_zero[500002]; int agg_a[500002]; int agg_b[500002]; int n; int q; int a; int b; int last_index_b_non_one; int last_index_a_non_zero; int x; int l; int r; long long current_value; int current_round; long long inverse_mod(long long value) { int exp = MOD_VALUE - 2; long long res = 1LL; long long base = value; while (exp > 0) { if (exp % 2 == 1) { res = (res * base) % MOD_VALUE; } base = (base * base) % MOD_VALUE; exp = exp / 2; } return res; } int main() { // read n & q scanf("%d %d", &n, &q); // read and precompute values (a, b) last_index_b_non_one = 0; last_index_a_non_zero = 0; simple_sum_a[0] = 0; just_b[0] = 1; agg_a[0] = 0; agg_b[0] = 1; for (int i = 1; i <= n; i++) { scanf("%d %d", &a, &b); // store b just_b[i] = b; // sum values a simple_sum_a[i] = simple_sum_a[i - 1] + (long long)a; // set next index where b > 1 if (b > 1) { for (int j = last_index_b_non_one; j < i; j++) { next_index_b_non_one[j] = i; } last_index_b_non_one = i; } // set next index where a > 0 if (a > 0) { for (int j = last_index_a_non_zero; j < i; j++) { next_index_a_non_zero[j] = i; } last_index_a_non_zero = i; } // aggregate parts a (additions) and b (multiplications), modulo 1000000007 if (b == 1) { // increase a part only (choose addition), if multiplier b == 1 agg_a[i] = (agg_a[i - 1] + a) % MOD_VALUE; } else { agg_a[i] = ((long long)agg_a[i - 1] * (long long)b) % MOD_VALUE; } agg_b[i] = ((long long)agg_b[i - 1] * (long long)b) % MOD_VALUE; } // set -1 for next index tables, to the end for (int j = last_index_b_non_one; j <= n; j++) { next_index_b_non_one[j] = -1; } for (int j = last_index_a_non_zero; j <= n; j++) { next_index_a_non_zero[j] = -1; } // printf("=== START - ARRAYS DUMP ===\n"); // printf("[i], just_b, simple_sum_a, next b>1, next a>0, agg_a, agg_b\n"); // for (int i = 0; i <= n; i++) { // printf("[%d] %d %lld %d %d %d %d\n", i, just_b[i], simple_sum_a[i], next_index_b_non_one[i], next_index_a_non_zero[i], agg_a[i], agg_b[i]); // } // printf("=== END - ARRAYS DUMP ===\n"); // process requests for (int i = 0; i < q; i++) { scanf("%d %d %d", &x, &l, &r); current_value = x; current_round = l; // printf("=== PROCESSING REQUEST %d ===\n", i); // special case for initial value == 0 - find first non zero a if (current_value == 0) { current_round = next_index_a_non_zero[current_round]; if ((current_round == -1) || (current_round > r)) { // no non zero a util the end (or, at least, until round r is reached) current_round = r; // printf("NO NON ZERO A UNTIL THE EXPECTED ROUND (OR UNTILE THE END AT ALL)!!!\n"); } current_value = simple_sum_a[current_round] - simple_sum_a[current_round - 1]; // printf("A ZERO SPECIAL CASE, curr_round=%d, curr_value=%lld\n", current_round, current_value); } // process kind of step by step, until surpass mod value while (current_round < r) { // add accumulated values a first (may be no-op in fact, if we have b>1 index after index, but it should result in adding 0) int temp_next_index_b_non_one = next_index_b_non_one[current_round]; if ((temp_next_index_b_non_one == -1) || (temp_next_index_b_non_one > r)) { // no b>1 until the end at all or until the end of expected round temp_next_index_b_non_one = r + 1; // a bit hacky, but it needs to point to the next value after the last expected round, to include the expected one } long long temp_diff = simple_sum_a[temp_next_index_b_non_one - 1] - simple_sum_a[current_round]; current_value = current_value + temp_diff; current_round = temp_next_index_b_non_one - 1; // minus 1, because that round is not processed yet after this step // printf("ADDING AGGREGATED SIMPLE SUM A DIFF; next_b_non_one=%d, diff=%lld, curr_round=%d, curr_value=%lld\n", temp_next_index_b_non_one, temp_diff, current_round, current_value); // if crossed mod value, break the loop now if (current_value >= MOD_VALUE) { current_value = current_value % MOD_VALUE; // printf("CROSSED MOD VALUE (A), BREAKING THE LOOP, curr_value=%lld, curr_round=%d\n", current_value, current_round); break; } // if reached the expected round, also break the loop if (current_round >= r) { // printf("REACHED EXPETED ROUND AFTER STEP A, curr_value=%lld, curr_round=%d\n", current_value, current_round); break; } // apply mutliplier b OR add a - depending what is better current_round = current_round + 1; long long temp_a = simple_sum_a[current_round] - simple_sum_a[current_round - 1]; // get value a back from sums long long temp_sum = current_value + temp_a; long long temp_multiply = current_value * (long long)just_b[current_round]; if (temp_sum > temp_multiply) { current_value = temp_sum; // printf("APPLIED ADDITION A, sum=%lld, multi=%lld, a=%lld, b=%d, curr_round=%d, curr_value=%lld\n", temp_sum, temp_multiply, temp_a, just_b[current_round], current_round, current_value); } else { current_value = temp_multiply; // printf("APPLIED MULTIPLY B, sum=%lld, multi=%lld, a=%lld, b=%d, curr_round=%d, curr_value=%lld\n", temp_sum, temp_multiply, temp_a, just_b[current_round], current_round, current_value); } // if crossed mod value, break the loop now if (current_value >= MOD_VALUE) { current_value = current_value % MOD_VALUE; // printf("CROSSED MOD VALUE (B), BREAKING THE LOOP, curr_value=%lld, curr_round=%d\n", current_value, current_round); break; } } // if current_round not achieved, it means that previous loop was broken (so we passed the mod value) if (current_round < r) { // so we need to apply "difference" multiplification of b (r "minus" current round), using inverse mod, and add diff of a (r "minus" current round) long long temp_b_r = agg_b[r]; long long temp_a_r = agg_a[r]; long long temp_b_curr = agg_b[current_round]; long long temp_a_curr = agg_a[current_round]; long long temp_b_curr_inv_mod = inverse_mod(temp_b_curr); long long temp_b_diff = (temp_b_r * temp_b_curr_inv_mod) % MOD_VALUE; long long temp_a_diff = ((temp_a_r - temp_a_curr * temp_b_diff) % MOD_VALUE + MOD_VALUE) % MOD_VALUE; current_value = (current_value * temp_b_diff + temp_a_diff) % MOD_VALUE; // printf("APPLIED DIFFS, b_r=%lld, a_r=%lld, b_curr=%lld, a_curr=%lld, b_curr_inv_mod=%lld, b_diff=%lld, a_diff=%lld, current_value=%lld\n", temp_b_r, temp_a_r, temp_b_curr, temp_a_curr, temp_b_curr_inv_mod, temp_b_diff, temp_a_diff, current_value); } // print value printf("%lld\n", current_value); } return 0; } |
English