其他分享
首页 > 其他分享> > 线段树 板子2 区间修改(加和乘)

线段树 板子2 区间修改(加和乘)

作者:互联网

线段树

这两题本质一样,就放在一起

P2023 [AHOI2009] 维护序列

https://www.luogu.com.cn/problem/P2023

时刻%p; query也别忘了pushdown;打错就完蛋

#include <iostream>
#include <algorithm>

using namespace std;
typedef long long LL;
const int N = 1e5 + 5;

int n, m, p;
LL a[N];

struct Node {
    int l, r;
    LL sum, add, mul;
}st[N * 4];

void pushup (int u) {
    st[u].sum = (st[u << 1].sum + st[u << 1 | 1].sum) % p;
}

void pushdown (int u) {
    auto &uu = st[u], &ll = st[u << 1], &rr = st[u << 1 | 1];
    //更新lazy
    ll.mul = (ll.mul * uu.mul) % p, ll.add = (ll.add * uu.mul + uu.add) % p;
    rr.mul = (rr.mul * uu.mul) % p, rr.add = (rr.add * uu.mul + uu.add) % p;
    //更新sum
    ll.sum = (ll.sum * uu.mul + (ll.r - ll.l + 1) * uu.add) % p;
    rr.sum = (rr.sum * uu.mul + (rr.r - rr.l + 1) * uu.add) % p; //一不小心打错就完蛋
    //reset uu
    uu.mul = 1, uu.add = 0;
}

void build (int u, int l, int r) {
    if (l == r) {
        st[u] = {l, r, a[r] % p, 0, 1};
        return;
    }
    st[u] = {l, r}, st[u].mul = 1, st[u].add = 0;
    int mid = l + r >> 1;
    build (u << 1, l, mid);
    build (u << 1 | 1, mid + 1, r);
    pushup (u);
}

void modify_mul (int u, int l, int r, LL k) {
    if (st[u].l >= l && st[u].r <= r) {
        st[u].add = (st[u].add * k) % p;
        st[u].mul = (st[u].mul * k) % p;
        st[u].sum = (st[u].sum * k) % p;
        return ;
    }

    pushdown (u);
    int mid = st[u].l + st[u].r >> 1;
    if (l <= mid)
        modify_mul (u << 1, l, r, k);
    if (r > mid)
        modify_mul (u << 1 | 1, l, r, k);
    pushup (u);
}

void modify_add (int u, int l, int r, LL k) {
    if (st[u].l >= l && st[u].r <= r) {
        st[u].add = (st[u].add + k) % p;
        st[u].sum = (st[u].sum + (st[u].r - st[u].l + 1) * k) % p; //+=
        return;
    }

    pushdown (u);
    int mid = st[u].l + st[u].r >> 1;
    if (l <= mid)
        modify_add (u << 1, l, r, k);
    if (r > mid)
        modify_add (u << 1 | 1, l, r, k);
    pushup (u);
}

LL query (int u, int l, int r) {
    if (st[u].l >= l && st[u].r <= r) {
        return st[u].sum % p;
    }

    pushdown (u);
    LL res = 0;
    int mid = st[u].l + st[u].r >> 1;
    if (l <= mid)
        res = (res + query (u << 1, l, r)) % p;
    if (r > mid)
        res = (res + query (u << 1 | 1, l, r)) % p;
    return res;
}

int main () {
    cin >> n >> p;
    for (int i = 1; i <= n; i ++)
        cin >> a[i];
    cin >> m;
    build (1, 1, n);

    while (m --) {
        int op, l, r, k;
        cin >> op >> l >> r;
        if (op == 1)
            cin >> k, modify_mul (1, l, r, k);
        else if (op == 2)
            cin >> k, modify_add (1, l, r, k);
        else
            cout << query (1, l, r) % p << endl;
    }
}

P3373 【模板】线段树 2

https://www.luogu.com.cn/problem/P3373

无处不在的细节问题,麻了。。。

#include <iostream>
#include <algorithm>

using namespace std;
const int N  = 1e5 + 5;
typedef long long LL;

int n, m, p;
LL a[N];

struct Node {
    int l, r;
    LL sum, add, mul;
}st[N * 4];

void pushup (int u) {
    st[u].sum = (st[u << 1].sum + st[u << 1 | 1].sum) % p;
}

void pushdown (int u) {
    auto &uu = st[u], &ll = st[u << 1], &rr = st[u << 1 | 1];
    //更新懒标记
    ll.add = (LL)(ll.add * uu.mul + uu.add) % p, rr.add = (LL)(rr.add * uu.mul + uu.add) % p;
    ll.mul *= uu.mul, rr.mul *= uu.mul;  ll.mul %= p, rr.mul %= p;
    //更新子树
    ll.sum = (LL)(ll.sum * uu.mul + (LL)(ll.r - ll.l + 1) * uu.add) % p;
    rr.sum = (LL)(rr.sum * uu.mul + (LL)(rr.r - rr.l + 1) * uu.add) % p;
    //更新父懒标记
    uu.mul = 1, uu.add = 0;
}

void build (int u, int l, int r) {
    if (l == r) {
        st[u] = {l, r, a[r] % p, 0, 1};
        return;
    }

    st[u] = {l, r}; //又忘了!!
    st[u].mul = 1;
    int mid = l + r >> 1;
    build (u << 1, l, mid);
    build (u << 1 | 1, mid + 1, r);
    pushup (u);
}

void modify_add (int u, int l, int r, LL v) {
    if (st[u].l >= l && st[u].r <= r) {
        st[u].add = (st[u].add + v) % p;
        st[u].sum = (st[u].sum + (st[u].r - st[u].l + 1) * v) % p;
        return;
    }

    pushdown (u);
    int mid = st[u].l + st[u].r >> 1;
    if (l <= mid)
        modify_add (u << 1, l, r, v);
    if (r > mid)
        modify_add (u << 1 | 1, l, r, v);
    pushup (u);
}

void modify_mul (int u, int l, int r, LL v) {
    // if (v == 1)
    //     return;
    if (st[u].l >= l && st[u].r <= r) {
        st[u].add = (st[u].add * v) % p;
        st[u].mul = (st[u].mul * v) % p;
        st[u].sum = (st[u].sum * v) % p;
        return ;
    }

    pushdown (u);
    int mid = st[u].l + st[u].r >> 1;
    if (l <= mid)
        modify_mul (u << 1, l, r, v);
    if (r > mid)
        modify_mul (u << 1 | 1, l, r, v);
    pushup (u);
}

LL query (int u, int l, int r) {
    if (st[u].l >= l && st[u].r <= r) {
        return st[u].sum % p;
    }

    pushdown (u);
    LL res = 0;
    int mid = st[u].l + st[u].r >> 1;
    if (l <= mid)
        res = (res + query (u << 1, l, r)) % p;
    if (r > mid)
        res = (res + query (u << 1 | 1, l, r)) % p;

    return res % p;
}

int main () {
    cin >> n >> m >> p;
    for (int i = 1; i <= n; i ++)
        cin >> a[i];
    build (1, 1, n);

    while (m --) {
        int op, x, y, k;
        cin >> op >> x >> y;
        if (op == 3)
            cout << query (1, x, y) % p << endl;
        else if (op == 2)
            cin >> k, modify_add (1, x, y, k);
        else
            cin >> k, modify_mul (1, x, y, k);
    }
    //主函数写错也是真无语
}

标签:int,线段,modify,cin,板子,op,st,LL,加和乘
来源: https://www.cnblogs.com/CTing/p/16076577.html