传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1798
注意,应保证当前节点维护的值是正确的,lazy tag只是一个下传标记,在下传时应即时更新儿子的维护值,在修改时也应即时更新当前节点的维护值。
#include <cstdio> const int maxn = 100005; int n, mod, a[maxn], m, t1, t2, t3, opr; struct Node { int ql, qr; long long sm, mul, add; } tree[maxn << 2]; inline void pushup(int p) { tree[p].sm = (tree[p << 1].sm + tree[p << 1 | 1].sm) % mod; } inline void pushdown(int p) { tree[p << 1].mul = tree[p << 1].mul * tree[p].mul % mod; tree[p << 1].add = (tree[p << 1].add * tree[p].mul + tree[p].add) % mod; tree[p << 1].sm = (tree[p << 1].sm * tree[p].mul + tree[p].add * (tree[p << 1].qr - tree[p << 1].ql + 1)) % mod; tree[p << 1 | 1].mul = tree[p << 1 | 1].mul * tree[p].mul % mod; tree[p << 1 | 1].add = (tree[p << 1 | 1].add * tree[p].mul + tree[p].add) % mod; tree[p << 1 | 1].sm = (tree[p << 1 | 1].sm * tree[p].mul + tree[p].add * (tree[p << 1 | 1].qr - tree[p << 1 | 1].ql + 1)) % mod; tree[p].mul = 1; tree[p].add = 0; } void make_tree(int p, int left, int right) { tree[p].ql = left; tree[p].qr = right; tree[p].mul = 1; if (left == right) { tree[p].sm = (long long)(a[left] % mod); return; } int mid = (left + right) >> 1; make_tree(p << 1, left, mid); make_tree(p << 1 | 1, mid + 1, right); pushup(p); } void mull(int p, int left, int right, int c) { if (tree[p].ql == left && tree[p].qr == right) { tree[p].mul = tree[p].mul * (long long)c % mod; tree[p].add = tree[p].add * (long long)c % mod; tree[p].sm = tree[p].sm * (long long)c % mod; return; } pushdown(p); int mid = (tree[p].ql + tree[p].qr) >> 1; if (right <= mid) { mull(p << 1, left, right, c); } else if (left > mid) { mull(p << 1 | 1, left, right, c); } else { mull(p << 1, left, mid, c); mull(p << 1 | 1, mid + 1, right, c); } pushup(p); } void addd(int p, int left, int right, int c) { if (tree[p].ql == left && tree[p].qr == right) { tree[p].add = (tree[p].add + (long long)c) % mod; tree[p].sm = (tree[p].sm + (long long)c * (long long)(tree[p].qr - tree[p].ql + 1)) % mod; return; } pushdown(p); int mid = (tree[p].ql + tree[p].qr) >> 1; if (right <= mid) { addd(p << 1, left, right, c); } else if (left > mid) { addd(p << 1 | 1, left, right, c); } else { addd(p << 1, left, mid, c); addd(p << 1 | 1, mid + 1, right, c); } pushup(p); } int qry(int p, int left, int right) { if (tree[p].ql == left && tree[p].qr == right) { return (int)tree[p].sm; } pushdown(p); int mid = (tree[p].ql + tree[p].qr) >> 1, rt; if (right <= mid) { rt = qry(p << 1, left, right); } else if (left > mid) { rt = qry(p << 1 | 1, left, right); } else { rt = qry(p << 1, left, mid); rt = (rt + qry(p << 1 | 1, mid + 1, right)) % mod; } pushup(p); return rt; } int main(void) { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); scanf("%d%d", &n, &mod); for (int i = 1; i <= n; ++i) { scanf("%d", a + i); } make_tree(1, 1, n); scanf("%d", &m); while (m--) { scanf("%d%d%d", &opr, &t1, &t2); if (opr == 1) { scanf("%d", &t3); mull(1, t1, t2, t3); } else if (opr == 2) { scanf("%d", &t3); addd(1, t1, t2, t3); } else { printf("%d ", qry(1, t1, t2)); } } return 0; }