题目地址:
https://www.luogu.com.cn/problem/P3373
题目描述:
如题,已知一个数列,你需要进行下面三种操作:
将某区间每一个数乘上
x
x
x
将某区间每一个数加上
x
x
x
求出某区间每一个数的和
输入格式:
第一行包含三个整数
n
,
m
,
p
n,m,p
n,m,p,分别表示该数列数字的个数、操作的总个数和模数。
第二行包含
n
n
n个用空格分隔的整数,其中第
i
i
i个数字表示数列第
i
i
i项的初始值。
接下来
m
m
m行每行包含若干个整数,表示一个操作,具体如下:
操作
1
1
1:格式:1 x y k
含义:将区间
[
x
,
y
]
[x,y]
[x,y]内每个数乘上
k
k
k
操作
2
2
2:格式:2 x y k
含义:将区间
[
x
,
y
]
[x,y]
[x,y]内每个数加上
k
k
k
操作
3
3
3:格式:3 x y
含义:输出区间
[
x
,
y
]
[x,y]
[x,y]内每个数的和对
p
p
p取模所得的结果
输出格式:
输出包含若干行整数,即为所有操作
3
3
3的结果。
数据范围:
对于
30
%
30\%
30%的数据:
n
≤
8
n \le 8
n≤8,
m
≤
10
m \le 10
m≤10
对于
70
%
70\%
70%的数据:
n
≤
1
0
3
n \le 10^3
n≤103,
m
≤
1
0
4
m \le 10^4
m≤104
对于
100
%
100\%
100%的数据:
n
≤
1
0
5
n \le 10^5
n≤105,
m
≤
1
0
5
m \le 10^5
m≤105
参考https://blog.csdn.net/qq_46105170/article/details/121469108。代码如下:
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int n, m;
long p, a[N];
struct Node {
int l, r;
long sum;
long mul, add;
} tr[N << 2];
void pushup(int u) {
tr[u].sum = (tr[u << 1].sum + tr[u << 1 | 1].sum) % p;
}
void update(Node &u, long mul, long add) {
u.mul = (u.mul * mul) % p;
u.add = (u.add * mul + add) % p;
u.sum = (u.sum * mul + add * (u.r - u.l + 1)) % p;
}
void pushdown(int u) {
update(tr[u << 1], tr[u].mul, tr[u].add);
update(tr[u << 1 | 1], tr[u].mul, tr[u].add);
tr[u].mul = 1, tr[u].add = 0;
}
void build(int u, int l, int r) {
tr[u] = {l, r, 0, 1, 0};
if (l == r) {
tr[u].sum = a[l];
return;
}
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
}
void modify(int u, int l, int r, long mul, long add) {
if (l <= tr[u].l && tr[u].r <= r) {
update(tr[u], mul, add);
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) modify(u << 1, l, r, mul, add);
if (r > mid) modify(u << 1 | 1, l, r, mul, add);
pushup(u);
}
long query(int u, int l, int r) {
if (l <= tr[u].l && tr[u].r <= r) return tr[u].sum;
pushdown(u);
long res = 0;
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) res = (res + query(u << 1, l, r)) % p;
if (r > mid) res = (res + query(u << 1 | 1, l, r)) % p;
return res;
}
int main() {
scanf("%d%d%ld", &n, &m, &p);
for (int i = 1; i <= n; i++) scanf("%ld", &a[i]);
build(1, 1, n);
while (m--) {
int op, l, r;
long x;
scanf("%d%d%d", &op, &l, &r);
if (op == 1) {
scanf("%ld", &x);
modify(1, l, r, x, 0);
} else if (op == 2) {
scanf("%ld", &x);
modify(1, l, r, 1, x);
} else printf("%ld\n", query(1, l, r));
}
}
预处理时间复杂度 O ( n ) O(n) O(n),每个操作时间复杂度 O ( log n ) O(\log n) O(logn),空间 O ( n ) O(n) O(n)。