题面: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\n", st.Query(1, N, l, r, 1)); } } return 0; }
原文:https://www.cnblogs.com/hnfms-jerry/p/solution-SegmentTree.html