洛谷 P3373 【模板】线段树 2

这道题可以照着我的前一个第一个模板进行修改。

不同的地方说一下吧:

首先就是在结构体上的改动,因为在这里操作又多了一个乘法运算,所以这里又多了一个mul标记,用处和add是一样的,惰性操作。

好了,接下来才是重头戏,在我们向下更新区间的时候,也就是写pushdown函数的时候,我们需要注意一点,那就是对于运算顺序的考虑。我们想一个情景,如果说一个区间又乘又加,我们会先算什么?当然是乘法,我们这里也是一样的,在更新区间和的时候,我们需要先乘以mul,然后再去考虑加上增量,这样才能符合题目要求,不要先加后乘,这样会造成问题。

另外,在更新数据的时候,我们还需要注意的就是,我们不要忘记取模操作。

好了,接下来还有一个小问题,就是在乘法的操作中,我们为什么要把标记add也要乘以mul呢?其实并没有很大的含义,我们知道,上一次操作之后,无论是标记add,还是标记mul,都会被pushdown归为初始值,这样才会不影响下一次操作。但是电脑难免会有一些异常的运行,比如说在乘和加同时运行的时候,这个操作就相当有用了。所以还是要加上的。

上代码:

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<cmath> 
#include<vector>
#include<algorithm>
#include<stack>
#include<queue>
#include<deque>
#include <iomanip>
#include<sstream>
#include<numeric>
#include<map>
#include<limits.h>
#include<unordered_map>
#include<set>
#define int long long
#define MAX 100010
#define inf 0x3f3f3f3f
#define _for(i,a,b) for(int i=a;i<(b);i++)
using namespace std;
typedef pair<int, int> PII;
int n, m,k;
int counts;
int dx[] = { 0,1,0,-1};
int dy[] = { 1,0,-1,0 };
int w[MAX];
struct node {
    int l, r;
    int sum, add, mul;
}tr[MAX*4+2];
void pushup(int p) {
    tr[p].sum = (tr[2 * p].sum + tr[p * 2 + 1].sum)%k;
}
void pushdown(int p) {
    tr[2 * p].sum = (tr[2 * p].sum * tr[p].mul + (tr[2 * p].r - tr[2 * p].l + 1) * tr[p].add) % k;
    tr[2 * p+1].sum = (tr[2 * p+1].sum * tr[p].mul + (tr[2 * p+1].r - tr[2 * p+1].l + 1) * tr[p].add) % k;
    tr[2 * p].add = (tr[p].add + tr[2 * p].add*tr[p].mul) % k;
    tr[2 * p + 1].add = (tr[p].add + tr[2 * p+1].add*tr[p].mul) % k;
    tr[2 * p].mul = (tr[p].mul * tr[2 * p].mul) % k;
    tr[2 * p + 1].mul = (tr[p].mul * tr[2 * p+1].mul) % k;
    tr[p].add = 0;
    tr[p].mul = 1;
}
void build(int p, int l, int r) {
    tr[p] = { l,r,w[l],0,1 };
    if (l == r) {
        tr[p].sum = w[l]%k;
        return;
    }
    int mid = l + r >> 1;
    build(2 * p, l, mid);
    build(2 * p + 1, mid + 1, r);
    pushup(p);
}
void updateAdd(int p, int x, int y, int add) {
    if (x <= tr[p].l && y >= tr[p].r) {
        tr[p].add = (tr[p].add+add)%k;
        tr[p].sum = (tr[p].sum + (tr[p].r - tr[p].l + 1) * add) % k;
        return;
    }
    int mid = tr[p].l + tr[p].r >> 1;
    pushdown(p);
    if (x <= mid) updateAdd(2 * p, x, y, add);
    if (y > mid) updateAdd(2 * p + 1, x, y, add);
    pushup(p);
}
void updateMul(int p, int x, int y, int mul) {
    if (x <= tr[p].l && y >= tr[p].r) {
        tr[p].sum = (tr[p].sum * mul) % k;
        tr[p].mul =(tr[p].mul*mul) % k;
        tr[p].add = (tr[p].add * mul) % k;
        return;
    }
    int mid = tr[p].l + tr[p].r >> 1;
    pushdown(p);
    if (x <= mid) updateMul(2 * p, x, y, mul);
    if (y > mid) updateMul(2 * p + 1, x, y, mul);
    pushup(p);
}
int quary(int p, int x, int y) {
    if (x <= tr[p].l && y >= tr[p].r)
        return tr[p].sum;
    int sum = 0;
    int mid = tr[p].l + tr[p].r >> 1;
    pushdown(p);
    if (x <= mid) sum = (quary(2 * p, x, y)+sum)%k;
    if (y > mid) sum = (quary(2 * p + 1, x, y)+sum)%k;
    return sum;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin >> n >> m >> k;
    _for(i, 1, n + 1)
        cin >> w[i];
    build(1, 1, n);
    while (m--) {
        int num;
        cin >> num;
        if (num == 1) {
            int x, y, u;
            cin >> x >> y >> u;
            updateMul(1, x, y, u);
        }
        else if (num == 2) {
            int x, y, add;
            cin >> x >> y >> add;
            updateAdd(1, x, y, add);
        }
        else {
            int x, y;
            cin >> x >> y;
            cout << quary(1, x, y) << endl;
        }
    }
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值