P2023 [AHOI2009]维护序列 - 线段树区间乘法加法

Posted zolrk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2023 [AHOI2009]维护序列 - 线段树区间乘法加法相关的知识,希望对你有一定的参考价值。

记得及时更新sum(每次修改都更新),写成一个update函数比较好,因为很多时候会忘了%
还有懒标记是标记在这个点本身上的
然后就是左儿子和右儿子一定要看清楚。。。
一个是n * 2 ,一个是 n * 2 + 1 ,涉及到这部分的代码一定要专注
乘法标记优先级大于加法,并且对加法标记也有作用
若要增加加法标记,先让乘法标记作用一下加法标记,再增加加法标记
然后注意乘法标记要初始化为乘法单位元,就是1
每次清空也要初始化为1,建树的时候注意初始化乘法标记

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 100000 + 10;
typedef long long ll;
int n,m,p,a[MAXN];
struct segment{
    ll mul, add, sum, siz;
}tr[MAXN*4];

void update(int now) {
    tr[now].sum = tr[now*2].sum + tr[now*2+1].sum;
    tr[now].sum %= p;
}

void build(int now, int l, int r) {
    tr[now].mul = 1;
    if(l == r) {
        tr[now].siz = 1;
        tr[now].sum = a[l];
        return;
    }
    int mid = l + r >> 1;
    build(now*2, l, mid);
    build(now*2+1, mid+1, r);
    tr[now].sum = tr[now*2].sum + tr[now*2+1].sum;
    tr[now].sum %= p;
    tr[now].siz = tr[now*2].siz + tr[now*2+1].siz;
}

void down(int now) {
    int mul = tr[now].mul;
    int add = tr[now].add;
    
    tr[now*2].sum *= mul;
    tr[now*2].sum %= p;
    tr[now*2].sum += add * tr[now*2].siz;
    tr[now*2].sum %= p;
    
    tr[now*2+1].sum *= mul;
    tr[now*2+1].sum %= p;
    tr[now*2+1].sum += add * tr[now*2+1].siz;
    tr[now*2+1].sum %= p;
    
    tr[now*2].mul *= mul;
    tr[now*2].add *= mul;
    tr[now*2].add += add;
    
    tr[now*2].mul %= p;
    tr[now*2].add %= p;
    
    tr[now*2+1].mul *= mul;
    tr[now*2+1].add *= mul;
    
    tr[now*2+1].add += add;
    tr[now*2+1].mul %= p;
    tr[now*2+1].add %= p;
    
    tr[now].mul = 1;
    tr[now].add = 0; 
}

void mul_modi(int now, int l, int r, int x, int y, int k) {
    if(x <= l && r <= y) {
        tr[now].sum *= k;
        tr[now].sum %= p;
        
        tr[now].mul *= k;
        tr[now].mul %= p;
        
        tr[now].add *= k;
        tr[now].add %= p;
        return;
    }
    down(now);
    int mid = l + r >> 1;
    if(x <= mid)
        mul_modi(now*2, l, mid, x, y, k);
    if(y > mid)
        mul_modi(now*2+1, mid+1, r, x, y, k);
    update(now);
}

void add_modi(int now, int l, int r, int x, int y, int k){
    if(x <= l && r <= y) {
        tr[now].sum += k * tr[now].siz;
        tr[now].sum %= p;
        
        tr[now].add += k;
        tr[now].add %= p;
        return;
    }
    down(now);
    int mid = l + r >> 1;
    if(x <= mid)
        add_modi(now*2, l, mid, x, y, k);
    if(y > mid)
        add_modi(now*2+1, mid+1, r, x, y, k);
    update(now);
}

ll query(int now, int l, int r, int x, int y) {
    if(x <= l && r <= y) {
        return tr[now].sum;
    }
    down(now);
    int mid = l + r >> 1;
    ll sum = 0;
    if(x <= mid) {
        sum += query(now*2, l, mid, x, y);
        sum %= p;
    }
    if(y > mid) {
        sum += query(now*2+1, mid+1, r, x, y);
        sum %= p;
    }
    return sum;
}
int main() {
    scanf("%d%d", &n, &p);
    for(int i=1; i<=n; i++) {
        scanf("%d", &a[i]);
    }
    build(1, 1, n);
    scanf("%d", &m);
    for(int i=1; i<=m; i++) {
        int cmd, x, y, c;
        scanf("%d", &cmd);
        if(cmd == 1) {//mul
            scanf("%d%d%d", &x, &y, &c);
            mul_modi(1, 1, n, x, y, c);
        } else if(cmd == 2) {
            scanf("%d%d%d", &x, &y, &c);
            add_modi(1, 1, n, x, y, c);
        } else {
            scanf("%d%d", &x, &y);
            printf("%lld
", query(1, 1, n, x, y));
        }
    }
    return 0;
}

以上是关于P2023 [AHOI2009]维护序列 - 线段树区间乘法加法的主要内容,如果未能解决你的问题,请参考以下文章

P2023 [AHOI2009]维护序列 (线段树区间修改查询)

[P2023][AHOI2009]维护序列(线段树)

P2023 [AHOI2009] 维护序列(线段树水题)

P2023 [AHOI2009]维护序列 - 线段树区间乘法加法

P3373 线段树乘法模板 P2023 [AHOI2009]维护序列

洛谷 P2023 [AHOI2009]维护序列