理解:懒标记只可能存在线段树的一层中,当子节点接受懒标记时,父节点完成更新任务,清除懒标记。
const int N = 1e5 + 5; int t; int m, n, p; int w[N]; struct node { int l, r; ll sum, add, mul; }tr[N*4]; void pushup(int u) { tr[u].sum = (tr[u << 1].sum + tr[u << 1 | 1].sum) % p; } void change(node &now,ll add,ll mul) { now.sum = (now.sum*mul + (ll)(now.r - now.l + 1)*add) % p; now.mul = now.mul*mul%p; now.add = (now.add*mul + add) % p; } void pushdown(int u)//向下更新 { change(tr[u << 1], tr[u].add, tr[u].mul); change(tr[u << 1 | 1], tr[u].add, tr[u].mul); tr[u].add = 0, tr[u].mul = 1;//往下传后,当前层清空懒标记 } void build(int u, int l, int r) { if (l == r)tr[u] = { l,l,w[l],0,1 }; else { tr[u] = { l,r,0,0,1 }; int mid = l + r >> 1; build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r); pushup(u); } } void modify(int u, int l, int r, int add, int mul) { if (tr[u].l >= l && tr[u].r <= r)change(tr[u], add, mul); //树中结点,打上懒标记,查询时会更新 else//继续往下走 { pushdown(u); int mid = tr[u].l + tr[u].r >> 1; if (l <= mid)modify(u << 1, l, r, add, mul); if (r > mid)modify(u << 1 | 1, l, r, add, mul); pushup(u); } } ll query(int u, int l, int r) { if (tr[u].l >= l && tr[u].r <= r)return tr[u].sum; pushdown(u);//往下走时通过懒标记,更新子节点 int mid = tr[u].l + tr[u].r >> 1; ll sum = 0; if (l <= mid)sum = sum+query(u << 1, l, r)%p; if (r > mid)sum += query(u << 1 | 1, l, r); return sum%p; } int main() { //freopen("in.txt", "r", stdin); scanf("%d%d", &n, &p); f(i, 1, n)scanf("%d", &w[i]); build(1, 1, n); scanf("%d", &m); int a, b,c,d; while (m--) { scanf("%d%d%d", &a, &b, &c); if (a == 1) { scanf("%d", &d); modify(1, b, c, 0, d); } else if (a == 2) { scanf("%d", &d); modify(1, b, c, d, 1); } else printf("%lld\n", query(1, b, c)); } return 0; }