luogu3373线段树2..支持区间加值和乘值的线段树

匿名 (未验证) 提交于 2019-12-03 00:39:02

题面: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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!