ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-03-30 13:32:54  阅读:181  来源: 互联网

标签:int 线段 modify cin 板子 op st LL 加和乘


线段树

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

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有