区间加法+区间乘法(2标记 Luogu
-
一开始只想到了开2个标记,但是看了题解才知道标记下传是有优先级的
-
按题目数据来如果是
-
先+后x: v a l = ( v a l + b ) ∗ k = v a l ∗ k + b ∗ k val = (val + b) * k = val*k+b*k val=(val+b)∗k=val∗k+b∗k
-
先x后+ : v a l = v a l ∗ k + b val = val * k + b val=val∗k+b
-
-
如何处理2个标记?
-
- 假设给数组
[1,2,3]
中1~3
加上2,然后乘3,然后加4
- 式子:
s u m = ( a [ 1 ] + 2 ) ∗ 3 + ( a [ 2 ] + 2 ) ∗ 3 + ( a [ 3 ] + 2 ) ∗ 3 sum=(a[1]+2)*3 + (a[2]+2)*3 + (a[3]+2)*3 sum=(a[1]+2)∗3+(a[2]+2)∗3+(a[3]+2)∗3;
s u m = ( a [ 1 ] + 2 + 4 ) ∗ 3 + ( a [ 2 ] + 2 + 4 ) ∗ 3 + ( a [ 3 ] + 2 + 4 ) ∗ 3 sum=(a[1]+2+4)*3+(a[2]+2+4)*3+(a[3]+2+4)*3 sum=(a[1]+2+4)∗3+(a[2]+2+4)∗3+(a[3]+2+4)∗3;
= ( a [ 1 ] + 2 ) ∗ 3 + 4 ∗ 3 + ( a [ 2 ] + 2 ) ∗ 3 + 4 ∗ 3 + ( a [ 3 ] + 2 ) ∗ 3 + 4 ∗ 3 ; =(a[1]+2)*3+4*3+(a[2]+2)*3+4*3+(a[3]+2)*3+4*3; =(a[1]+2)∗3+4∗3+(a[2]+2)∗3+4∗3+(a[3]+2)∗3+4∗3;
- 但是先乘后加 用在 本该先加后乘 的情况下不成立:
s u m = ( a [ 1 ] + 2 ) ∗ 3 + 4 + ( a [ 2 ] + 2 ) ∗ 3 + 4 + ( a [ 3 ] + 2 ) ∗ 3 + 4 sum=(a[1]+2)*3+4+(a[2]+2)*3+4+(a[3]+2)*3+4 sum=(a[1]+2)∗3+4+(a[2]+2)∗3+4+(a[3]+2)∗3+4
- 除非
s u m = ( a [ 1 ] + 2 + 4 / 3 ) ∗ 3 + ( a [ 2 ] + 2 + 4 / 3 ) ∗ 3 + ( a [ 3 ] + 2 + 4 / 3 ) ∗ 3 sum=(a[1]+2+4/3)*3+(a[2]+2+4/3)*3+(a[3]+2+4/3)*3 sum=(a[1]+2+4/3)∗3+(a[2]+2+4/3)∗3+(a[3]+2+4/3)∗3
- 但是实数不好处理,所以规定标记下传优先级都为先乘后加 (将先加后乘转化过来)
s u m = ( a [ 1 ] ∗ 3 + 2 ∗ 3 + 4 ) + ( a [ 2 ] ∗ 3 + 2 ∗ 3 + 4 ) + ( a [ 3 ] ∗ 3 + 2 ∗ 3 + 4 ) sum=(a[1]*3+2*3+4)+(a[2]*3+2*3+4)+(a[3]*3+2*3+4) sum=(a[1]∗3+2∗3+4)+(a[2]∗3+2∗3+4)+(a[3]∗3+2∗3+4)
// 儿子的倍数都乘k了,那么儿子的add标记都要变大k倍,且加上父节点的add标记
multi[p<<1] = (multi[p<<1] * k) % mod;
multi[p<<1|1] = (multi[p<<1|1] * k) % mod;
add[p<<1] = (add[p<<1]*k + b) % mod;
add[p<<1|1] = (add[p<<1|1]*k + b) % mod;
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 4e5+10;
int a[maxn/4],left_[maxn],right_[maxn];
ll add[maxn],multi[maxn],sum[maxn];
ll mod;
void pushup(int p) { sum[p] = (sum[p<<1] + sum[p<<1|1]) % mod; }
void pushdown(int p) {
ll k = multi[p],b=add[p];
sum[p<<1] = (sum[p<<1]*k + b*(right_[p<<1] - left_[p<<1] + 1)) % mod;
sum[p<<1|1] = (sum[p<<1|1]*k + b*(right_[p<<1|1] - left_[p<<1|1] + 1)) % mod;
multi[p<<1] = (multi[p<<1] * k) % mod;
multi[p<<1|1] = (multi[p<<1|1] * k) % mod;
add[p<<1] = (add[p<<1]*k + b) % mod;
add[p<<1|1] = (add[p<<1|1]*k + b) % mod;
multi[p] = 1;
add[p] = 0;
}
void build(int p,int l,int r) {
multi[p] = 1,add[p]=0;
left_[p]=l,right_[p]=r;
if (l == r) {
sum[p] = a[l];
return ;
}
int mid = (l + r) >> 1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void change(int p,int l,int r,ll val) {
if (l<=left_[p] && right_[p]<=r) {
sum[p] = (sum[p] + val * (right_[p] - left_[p] + 1)) % mod;
add[p] = (add[p] + val) % mod;
return ;
}
pushdown(p);
int mid = (left_[p] + right_[p]) >> 1;
if (l <= mid)
change(p<<1,l,r,val);
if (mid < r)
change(p<<1|1,l,r,val);
pushup(p);
}
void multiple(int p,int l,int r,ll val) {
if (l<=left_[p] && right_[p]<=r) {
sum[p] = (sum[p] * val) % mod;
multi[p] = (multi[p] * val) % mod;
add[p] = (add[p] * val) % mod;
return ;
}
pushdown(p);
int mid = (left_[p] + right_[p]) >> 1;
if (l <= mid)
multiple(p<<1,l,r,val);
if (mid < r)
multiple(p<<1|1,l,r,val);
pushup(p);
}
ll query(int p,int l,int r) {
if (l<=left_[p] && right_[p]<=r)
return sum[p] % mod;
pushdown(p);
ll ans = 0;
int mid = (left_[p] + right_[p]) >> 1;
if (l <= mid)
ans = query(p<<1,l,r) % mod;
if (mid < r)
ans = (ans + query(p<<1|1,l,r)) % mod;
return ans % mod;
}
int n,m;
int main() {
[](){
::ios::sync_with_stdio(false);
::cin.tie(0);
::cout.tie(0);
}();
cin >> n >> m >> mod;
for (int i=1; i<=n; ++i)
cin >> a[i];
build(1,1,n);
while(m--) {
int index,x,y;
ll k;
cin >> index;
if (index == 1) {
cin >> x >> y >> k;
multiple(1,x,y,k);
} else if (index == 2) {
cin >> x >> y >> k;
change(1,x,y,k);
} else {
cin >> x >> y;
cout << query(1,x,y) << "\n";
}
}
return 0;
}