Portal
Portal1: BZOJ
Portal2: Luogu
Description
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。
有长为$N$的数列,不妨设为$a_1, a_2, \dots , a_N$。
有如下三种操作形式:
把数列中的一段数全部乘一个值;
把数列中的一段数全部加一个值;
询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模$P$的值。
Input
第一行两个整数$N$和$P$($1 \le P \le 1000000000$)。
第二行含有N个非负整数,从左到右依次为$a_1, a_2, \dots , a_N$,($0 \le ai \le 1000000000,1 \le i \le N$)。
第三行有一个整数$M$,表示操作总数。
从第四行开始每行描述一个操作,输入的操作有以下三种形式:
操作$1$:1 t g c
。表示把所有满足$t \le i \le g$的$a_i$改为$ai \times c$($1 \le t \le g \le N, 0 \le c \le 1000000000$)。
操作$2$: 2 t g c
。表示把所有满足$t \le i \le g$的$a_i$改为$ai + c$($1 \le t \le g \le N, 0 \le c \le 1000000000$)。
操作$3$: 3 t g
。询问所有满足$t \le i \le g$的$a_i$的和模$P$的值($1 \le t \le g \le N$)。
同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。
Output
对每个操作$3$,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
Sample Input
7 43
1 2 3 4 5 6 7
5
1 2 5 5
3 2 4
2 3 7 9
3 1 3
3 4 7
###Sample Output
2
35
8
Sample Explain
初始时数列为$(1, 2, 3, 4, 5, 6, 7)$。
经过第$1$次操作后,数列为$(1, 10, 15, 20, 25, 6, 7)$。
对第$2$次操作,和为$10 + 15 + 20 = 45$,模$43$的结果是$2$。
经过第$3$次操作后,数列为$(1, 10, 24, 29, 34, 15, 16)$
对第$4$次操作,和为$1 + 10 + 24 = 35$,模$43$的结果是$35$。
对第$5$次操作,和为$29 + 34 + 15 + 16 = 94$,模$43$的结果是$8$。
Hint
数据编号 | N | M |
---|---|---|
1 | 10 | 10 |
2 | 1000 | 1000 |
3 | 1000 | 1000 |
4 | 10000 | 10000 |
5 | 60000 | 60000 |
6 | 70000 | 70000 |
7 | 80000 | 80000 |
8 | 90000 | 90000 |
9 | 100000 | 100000 |
10 | 100000 | 100000 |
Solution
线段树模板题,区间加法,区间乘法,区间求和。
Code
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
const int MAXN = 500005;
int n, m, mod, opt, x, y, val;
LL a[MAXN], sum[MAXN], Mul[MAXN], Add[MAXN];
inline void pushup(LL x) {
sum[x] = (sum[x << 1] + sum[x << 1 | 1]) % mod;
}
inline void pushdown(LL l, LL r, LL root) {//下传懒标记
LL mid = (l + r) >> 1;
sum[root << 1] = (sum[root << 1] * Mul[root] + Add[root] * (mid - l + 1)) % mod;
sum[root << 1 | 1] = (sum[root << 1 | 1] * Mul[root] + Add[root] * (r - mid)) % mod;
Mul[root << 1] = (Mul[root << 1] * Mul[root]) % mod;
Mul[root << 1 | 1] = (Mul[root << 1 | 1] * Mul[root]) % mod;
Add[root << 1] = (Add[root << 1] * Mul[root] + Add[root]) % mod;
Add[root << 1 | 1] = (Add[root << 1 | 1] * Mul[root] + Add[root]) % mod;
Mul[root] = 1; Add[root] = 0;
}
inline void build(LL l, LL r, LL root) {//建树
Mul[root] = 1; Add[root] = 0;
if (l==r) sum[root] = a[l]; else {
LL mid = (l + r) >> 1;
build(l, mid, root << 1);
build(mid + 1, r, root << 1 | 1);
pushup(root);
}
sum[root] %= mod;
}
inline void update_mul(LL ansl, LL ansr, LL val, LL l, LL r, LL root) {//区间乘法
if (ansr < l || r < ansl) return ;
if (ansl <= l && r <= ansr) {
sum[root] = (sum[root] * val) % mod;
Mul[root] = (Mul[root] * val) % mod;
Add[root] = (Add[root] * val) % mod;
return ;
}
pushdown(l, r, root);
LL mid = (l + r) >> 1;
update_mul(ansl, ansr, val, l, mid, root << 1);
update_mul(ansl, ansr, val, mid + 1, r, root << 1 | 1);
pushup(root);
}
inline void update_add(LL ansl, LL ansr, LL val, LL l, LL r, LL root) {//区间加法
if (ansr < l || r < ansl) return ;
if (ansl <= l && r <= ansr) {
Add[root] = (Add[root] + val) % mod;
sum[root] = (sum[root] + val * (r - l + 1)) % mod;
return ;
}
pushdown(l, r, root);
LL mid = (l + r) >> 1;
update_add(ansl, ansr, val, l, mid, root << 1);
update_add(ansl, ansr, val, mid + 1, r, root << 1 | 1);
pushup(root);
}
inline LL query(LL ansl, LL ansr, LL l, LL r, LL root) {//区间询问
if (ansr < l || r < ansl) return 0;
if (ansl <= l && r <= ansr) return sum[root];
pushdown(l, r, root);
LL mid = (l + r) >> 1;
return (query(ansl, ansr, l, mid, root << 1) + query(ansl, ansr, mid + 1, r, root << 1 | 1)) % mod;
}
int main() {
scanf("%d%d", &n, &mod);
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
build(1, n, 1);
scanf("%d", &m);
for (int i = 1; i <= m; i++) {
scanf("%d", &opt);
if (opt == 1) {
scanf("%d%d%d", &x, &y, &val);
update_mul(x, y, val, 1, n, 1);
} else
if (opt == 2) {
scanf("%d%d%d", &x, &y, &val);
update_add(x, y, val, 1, n, 1);
} else
if (opt == 3) {
scanf("%d%d", &x, &y);
printf("%lld\n", query(x, y, 1, n, 1));
}
}
return 0;
}
Attachment
Article Author: XiaoHuang