luogu3373线段树2..支持区间加值和乘值的线段树
Posted hnfms-jerry
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu3373线段树2..支持区间加值和乘值的线段树相关的知识,希望对你有一定的参考价值。
这道题调了2个多小时发现有个地方模运算符号弄错了...
题面:luogu3373
和线段树1一样,这道题也要用Lazy标记思想,这个很好理解.
不过重点在更新的顺序上面:
因为乘法优先,所以每次执行PushDown操作时要先算乘法.
再就是注意到对于乘法的标记,每次要更新的不仅是乘法的,还有加法的标记.
另外,一定要注意模运算的符号!!!
#include <cstdio>
using namespace std;
typedef long long ll;
const int MAXN = 1e5;
struct SegmentTree {
ll mod, N, su[MAXN * 4 + 10], ad[MAXN * 4 + 10], ml[MAXN * 4 + 10];
void init() {
for(int i = 1; i <= N * 4; ++i)
ml[i] = 1;
}
void PushDownPls(ll pos, ll numl, ll numr) {
if(ad[pos] == 0) return;
ad[pos << 1] = (ad[pos << 1] + ad[pos]) % mod;
ad[pos << 1 | 1] = (ad[pos << 1 | 1] + ad[pos]) % mod;
su[pos << 1] = (su[pos << 1] + ad[pos] * numl % mod) % mod;
su[pos << 1 | 1] = (su[pos << 1 | 1] + ad[pos] * numr % mod) % mod;
ad[pos] = 0;
}
void PushDownMul(ll pos, ll numl, ll numr) {
if(ml[pos] == 1) return;
ml[pos << 1] = (ml[pos << 1] * ml[pos]) % mod;
ml[pos << 1 | 1] = (ml[pos << 1 | 1] * ml[pos]) % mod;
su[pos << 1] = (su[pos << 1] * ml[pos]) % mod;
su[pos << 1 | 1] = (su[pos << 1 | 1] * ml[pos]) % mod;
ad[pos << 1] = (ad[pos << 1] * ml[pos]) % mod;
ad[pos << 1 | 1] = (ad[pos << 1 | 1] * ml[pos]) % mod;
ml[pos] = 1;
}
void UpdatePls(ll l, ll r, ll L, ll R, ll val, ll pos) {
if(L <= l && r <= R) {
su[pos] = (su[pos] + val * (r - l + 1)) % mod;
ad[pos] = (ad[pos] + val) % mod;
return;
}
ll m = (l + r) / 2;
PushDownMul(pos, m - l + 1, r - m);
PushDownPls(pos, m - l + 1, r - m);
if(L <= m) UpdatePls(l, m, L, R, val, pos << 1);
if(R > m) UpdatePls(m + 1, r, L, R, val, pos << 1 | 1);
su[pos] = (su[pos << 1] + su[pos << 1 | 1]) % mod;
}
void UpdateMul(ll l, ll r, ll L, ll R, ll val, ll pos) {
if(L <= l && r <= R) {
su[pos] = (su[pos] * val) % mod;
ml[pos] = (ml[pos] * val) % mod;
ad[pos] = (ad[pos] * val) % mod;
return;
}
ll m = (l + r) / 2;
PushDownMul(pos, m - l + 1, r - m);
PushDownPls(pos, m - l + 1, r - m);
if(L <= m) UpdateMul(l, m, L, R, val, pos << 1);
if(R > m) UpdateMul(m + 1, r, L, R, val, pos << 1 | 1);
su[pos] = (su[pos << 1] + su[pos << 1 | 1]) % mod;
}
ll Query(ll l, ll r, ll L, ll R, ll pos) {
if(L <= l && r <= R)
return su[pos] % mod;
ll m = (l + r) / 2, sum = 0;
PushDownMul(pos, m - l + 1, r - m);
PushDownPls(pos, m - l + 1, r - m);
if(L <= m) sum = (sum + Query(l, m, L, R, pos << 1)) % mod;
if(R > m) sum = (sum + Query(m + 1, r, L, R, pos << 1 | 1)) % mod;
return sum;
}
};
ll N, M, K;
SegmentTree st;
int main() {
scanf("%lld%lld%lld", &N, &M, &K);
st.mod = K, st.N = N;
st.init();
for(ll i = 1, v; i <= N; ++i) {
scanf("%lld", &v);
st.UpdatePls(1, N, i, i, v, 1);
}
for(ll i = 1, z, l, r, v; i <= M; ++i) {
scanf("%lld", &z);
if(z == 1) {
scanf("%lld%lld%lld", &l, &r, &v);
st.UpdateMul(1, N, l, r, v, 1);
} else if(z == 2) {
scanf("%lld%lld%lld", &l, &r, &v);
st.UpdatePls(1, N, l, r, v, 1);
} else if(z == 3) {
scanf("%lld%lld", &l, &r);
printf("%lld
", st.Query(1, N, l, r, 1));
}
}
return 0;
}
以上是关于luogu3373线段树2..支持区间加值和乘值的线段树的主要内容,如果未能解决你的问题,请参考以下文章