众所周知,线段树是非常难调的,所以,求助 daolao:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 4e5 + 5;
int n, m, p;
int d[N], l1[N], l2[N], a[N];
void F(int node, int l, int r, int add, int mul){
d[node] = ((r - l + 1) * add % p + d[node] * mul % p) % p;
l2[node] = l2[node] % p * mul % p;
l1[node] = (add + l1[node] * mul % p) % p;
}
void push_up(int node){
d[node] = (d[node << 1] % p + d[(node << 1) + 1] % p) % p;
}
void push_down(int l, int r, int node){
int mid = l + r >> 1;
F(node << 1, l, mid, l1[node], l2[node]);
F((node << 1) + 1, mid + 1, r, l1[node], l2[node]);
l1[node] = 0;
l2[node] = 1;
}
void build(int l, int r, int node){
l2[node] = 1;
l1[node] = 0;
if(l == r){
d[node] = a[l];
return ;
}
int mid = l + r >> 1;
build(l, mid, node << 1);
build(mid + 1, r, (node << 1) + 1);
push_up(node);
}
void update(int l, int r, int s, int t, int node, int add, int mul){
if(l <= s && t <= r){
F(node, s, t, add, mul);
return ;
}
push_down(s, t, node);
int mid = s + t >> 1;
if(l <= mid){
update(l, r, s, mid, node << 1, add, mul);
}
if(mid + 1 <= mid){
update(l, r, mid + 1, t, (node << 1) + 1, add, mul);
}
push_up(node);
}
int query(int l, int r, int s, int t, int node){
if(l <= s && t <= r){
return d[node] % p;
}
push_down(s, t, node);
int sum = 0, mid = s + t >> 1;
if(l <= mid){
sum += query(l, r, s, mid, node << 1);
sum %= p;
}
if(mid + 1 <= r){
sum += query(l, r, mid + 1, t, (node << 1) + 1);
sum %= p;
}
return sum % p;
}
signed main(){
cin >> n >> m >> p;
for(int i = 1; i <= n; i++){
cin >> a[i];
}
build(1, n, 1);
while(m--){
int op;
cin >> op;
if(op == 1){
int x, y, k;
cin >> x >> y >> k;
update(x, y, 1, n, 1, 0, k);
}
else if(op == 2){
int x, y, k;
cin >> x >> y >> k;
update(x, y, 1, n, 1, k, 1);
}
else{
int x, y;
cin >> x >> y;
cout << query(x, y, 1, n, 1) % p << endl;
}
}
return 0;
}