P3373 【模板】线段树 2 区间更新乘法+区间求和

该博客介绍了如何使用线段树处理区间更新乘法和区间求和的问题,包括操作类型、输入输出格式以及数据范围,并提供了样例解释懒标记更新的处理方式。
摘要由CSDN通过智能技术生成

题目描述
如题,已知一个数列,你需要进行下面三种操作:

将某区间每一个数乘上 xx

将某区间每一个数加上 xx

求出某区间每一个数的和

输入格式
第一行包含三个整数 n,m,pn,m,p,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。

接下来 mm 行每行包含若干个整数,表示一个操作,具体如下:

操作 11: 格式:1 x y k 含义:将区间 [x,y][x,y] 内每个数乘上 kk

操作 22: 格式:2 x y k 含义:将区间 [x,y][x,y] 内每个数加上 kk

操作 33: 格式:3 x y 含义:输出区间 [x,y][x,y] 内每个数的和对 pp 取模所得的结果

输出格式
输出包含若干行整数,即为所有操作 33 的结果。

输入输出样例
输入 #1复制
5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4
输出 #1复制
17
2
说明/提示
【数据范围】

对于 30%30% 的数据:n \le 8n≤8,m \le 10m≤10
对于 70%70% 的数据:n \le 10^3n≤10
3
,m \le 10^4m≤10
4

对于 100%100% 的数据:n \le 10^5n≤10
5
,m \le 10^5m≤10
5

除样例外,p = 571373p=571373

(数据已经过加强_

样例说明:在这里插入图片描述
故输出应为 1717、22( 40 \bmod 38 = 240mod38=2 )

乘法板子与加法、替换等不同,是对于懒标记进行先乘后加的操作,主要对懒标记和树上节点的更新

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <map>
#include <stack>
#include <set>
#include <queue>
#include <vector>

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>

#define inf 0x3f3f3f3f
#define cha 1e-6
#define ll long long
using namespace std;
const int maxn = 1e5 + 6;
ll node[400005],lazy[400005],mul[400005];
ll a[100005];
ll mod;
ll read() {
  ll w = 1, q = 0;
  char ch = ' ';
  while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
  if (ch == '-') w = -1, ch = getchar();
  while (ch >= '0' && ch <= '9') q = (ll)q * 10 + ch - '0', ch = getchar();
  return (ll)w * q;
}
int n, m;
void up(ll i) { node[i] = (node[(i << 1)] + node[(i << 1) | 1]) % mod; }
void pd(ll i, ll s, ll t) {
  ll l = (i << 1), r = (i << 1) | 1, mid = (s + t) >> 1;
  if (mul[i] != 1) {
    mul[l] *= mul[i];mul[l] %= mod;
    mul[r] *= mul[i];mul[r] %= mod;
    lazy[l] *= mul[i];lazy[l] %= mod;
    lazy[r] *= mul[i];lazy[r] %= mod;
    node[l] *= mul[i];node[l] %= mod;
    node[r] *= mul[i];node[r] %= mod;
    mul[i] = 1;
  }
  if (lazy[i]) {
    node[l] += lazy[i] * (mid - s + 1);node[l] %= mod;
    node[r] += lazy[i] * (t - mid);node[r] %= mod;
    lazy[l] += lazy[i];lazy[l] %= mod;
    lazy[r] += lazy[i];lazy[r] %= mod;
    lazy[i] = 0;
  }
  return;
}
void build(ll s, ll t, ll i) {
  mul[i] = 1;
  if (s == t) {
    node[i] = a[s];
    return;
  }
  ll mid = (s + t) >> 1;
  build(s, mid, i << 1);
  build(mid + 1, t, (i << 1) | 1);
  up(i);
}
inline void updatemul(ll l, ll r, ll s, ll t, ll p, ll z) {
    ll mid = (s + t) >> 1;
    if (l <= s && t <= r) {
        mul[p] *= z;mul[p] %= mod;
        lazy[p] *= z;lazy[p] %= mod;
        node[p] *= z;node[p] %= mod;
        return;
    }
    pd(p, s, t);
    if (mid >= l) updatemul(l, r, s, mid, (p << 1), z);
    if (mid + 1 <= r) updatemul(l, r, mid + 1, t, (p << 1) | 1, z);
    up(p);
}
inline void updateplus(ll l, ll r, ll s, ll t, ll p, ll z) {
    ll mid = (s + t) >> 1;
    if (l <= s && t <= r) {
        node[p] += z * (t - s + 1);node[p] %= mod;
        lazy[p] += z;lazy[p] %= mod;
        return;
    }
    pd(p, s, t);
    if (mid >= l) updateplus(l, r, s, mid, (p << 1), z);
    if (mid + 1 <= r) updateplus(l, r, mid + 1, t, (p << 1) | 1, z);
    up(p);
}
inline ll getsum(ll l, ll r, ll s, ll t, ll p) {
    ll mid = (s + t) >> 1;
    ll sum = 0;
    if (l <= s && t <= r) return node[p];
    pd(p, s, t);
    if (mid >= l) sum += getsum(l, r, s, mid, (p << 1));
    sum %= mod;
    if (mid + 1 <= r) sum += getsum(l, r, mid + 1, t, (p << 1) | 1);
    return sum % mod;
}
int  main() {
  ll i, j, x, y, bh;
  ll z;
  n = read();
  m = read();
  mod = read();
  for (i = 1; i <= n; i++) a[i] = read();
  build(1, n, 1);
  for (i = 1; i <= m; i++) {
    bh = read();
    if (bh == 1) {
      x = read();
      y = read();
      z = read();
      updatemul(x, y, 1, n, 1, z);
    } else if (bh == 2) {
      x = read();
      y = read();
      z = read();
      updateplus(x, y, 1, n, 1, z);
    } else if (bh == 3) {
      x = read();
      y = read();
      printf("%lld\n", getsum(x, y, 1, n, 1));
    }
  }
  system("pause");
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值