题目描述
如题,已知一个数列,你需要进行下面三种操作:
-
将某区间每一个数乘上 x
-
将某区间每一个数加上 x
-
求出某区间每一个数的和
输入格式
第一行包含三个整数 n,m,p分别表示该数列数字的个数、操作的总个数和模数。
第二行包含 n 个用空格分隔的整数,其中第 i 个数字表示数列第 i 项的初始值。
接下来 m 行每行包含若干个整数,表示一个操作,具体如下:
操作 1: 格式:1 x y k
含义:将区间 [x,y]内每个数乘上 k
操作 2: 格式:2 x y k
含义:将区间 [x,y] 内每个数加上 k
操作 3: 格式:3 x y
含义:输出区间 [x,y] 内每个数的和对 p 取模所得的结果
输出格式
输出包含若干行整数,即为所有操作 3 的结果。
输入输出样例
输入 #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
暂且当个板子记录一下(* ̄︶ ̄)
线段树写法:
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5 + 7;
int p;
long long a[N];
struct node
{
long long v, mul, add;
}st[N << 2];
void build(int root, int l, int r)
{
st[root].mul = 1;
st[root].add = 0;
if (l == r) {
st[root].v = a[l];
}
else {
int m = (l + r) / 2;
build(root << 1, l, m);
build(root << 1 | 1, m + 1, r);
st[root].v = st[root << 1].v + st[root << 1 | 1].v;
}
st[root].v %= p;
return;
}
void pushdown(int root, int l, int r)
{
int m = (l + r) / 2;
st[root << 1].v = (st[root << 1].v * st[root].mul + st[root].add * (m - l + 1)) % p;
st[root << 1 | 1].v = (st[root << 1 | 1].v * st[root].mul + st[root].add * (r - m)) % p;
st[root << 1].mul = (st[root << 1].mul * st[root].mul) % p;
st[root << 1 | 1].mul = (st[root << 1 | 1].mul * st[root].mul) % p;
st[root << 1].add = (st[root << 1].add * st[root].mul + st[root].add) % p;
st[root << 1 | 1].add = (st[root << 1 | 1].add * st[root].mul + st[root].add) % p;
st[root].mul = 1;
st[root].add = 0;
return;
}
void mul(int root, int stdl, int stdr, int l, int r, long long k)
{
if (r < stdl || stdr < l)
return;
if (l <= stdl && stdr <= r)
{
st[root].v = (st[root].v * k) % p;
st[root].mul = (st[root].mul * k) % p;
st[root].add = (st[root].add * k) % p;
return;
}
pushdown(root, stdl, stdr);
int m = (stdl + stdr) / 2;
mul(root << 1, stdl, m, l, r, k);
mul(root << 1 | 1, m + 1, stdr, l, r, k);
st[root].v = (st[root << 1].v + st[root << 1 | 1].v) % p;
return;
}
void add(int root, int stdl, int stdr, int l, int r, long long k)
{
if (r < stdl || stdr < l)
return;
if (l <= stdl && stdr <= r)
{
st[root].add = (st[root].add + k) % p;
st[root].v = (st[root].v + k * (stdr - stdl + 1)) % p;
return;
}
pushdown(root, stdl, stdr);
int m = (stdl + stdr) / 2;
add(root << 1, stdl, m, l, r, k);
add(root << 1 | 1, m + 1, stdr, l, r, k);
st[root].v = (st[root << 1].v + st[root << 1 | 1].v) % p;
return;
}
long long query(int root, int stdl, int stdr, int l, int r)
{
if (r < stdl || stdr < l)
return 0;
if (l <= stdl && stdr <= r)
return st[root].v;
pushdown(root, stdl, stdr);
int m = (stdl + stdr) / 2;
return (query(root << 1, stdl, m, l, r) + query(root << 1 | 1, m + 1, stdr, l, r)) % p;
}
void solve()
{
int n, m;
scanf("%d%d%d", &n, &m, &p);
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
build(1, 1, n);
while (m--)
{
int chk;
scanf("%d", &chk);
int x, y;
long long k;
if (chk == 1)
{
scanf("%d%d%lld", &x, &y, &k);
mul(1, 1, n, x, y, k);
}
else if (chk == 2)
{
scanf("%d%d%lld", &x, &y, &k);
add(1, 1, n, x, y, k);
}
else
{
scanf("%d%d", &x, &y);
printf("%lld\n", query(1, 1, n, x, y));
}
}
}
int main()
{
solve();
return 0;
}
分块写法:
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <iomanip>
#include <cmath>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define bug(x) cout<<#x<<"=="<<x<<endl;
using namespace std;
typedef long long ll;
typedef vector<int> VI;
typedef pair<int, int> PII;
const int maxn = 1e5 + 5;
ll mod;
ll n, m;
ll num;//块的数量
ll l[maxn], r[maxn];//第i个数所在的块最左,最右的点
ll len[maxn], belong[maxn];//len表示第i块的大小,belong表示第i个数所在的块是第几块
ll a[maxn], sum[maxn];//第i块的和
ll tag[maxn];//每个整块加的数
ll mul[maxn];//每个整块乘的数
inline int read() {
int s = 0, w = 1; char ch = getchar();
while (ch < '0' || ch>'9') { if (ch == '-') w = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
inline void write(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
void build() {//建块
num = sqrt(n);
for (int i = 1; i <= num; ++i) {
l[i] = n / num * (i - 1) + 1;
r[i] = n / num * i;
}
r[num] = n;
for (int i = 1; i <= num; ++i) {
for (int j = l[i]; j <= r[i]; ++j) {
belong[j] = i;
}
}
for (int i = 1; i <= num; ++i) {
len[i] = r[i] - l[i] + 1;
}
for (int i = 1; i <= num; ++i) {
for (int j = l[i]; j <= r[i]; ++j) {
sum[i] += a[j];
}
}
}
void pushdown(int x) {//下传
for (int i = l[x]; i <= r[x]; ++i) {
a[i] = (a[i] * mul[x] + tag[x]) % mod;
}
tag[x] = 0; mul[x] = 1;
}
void add(int x, int y, int k) {
if (belong[x] == belong[y]) {
pushdown(belong[x]);
for (int i = x; i <= y; ++i) { a[i] = a[i] + k; sum[belong[i]] = (sum[belong[i]] + k) % mod; }
}
else {
pushdown(belong[x]);
for (int i = x; i <= r[belong[x]]; ++i) { a[i] = a[i] + k; sum[belong[i]] = (sum[belong[i]] + k) % mod; }
pushdown(belong[y]);
for (int i = l[belong[y]]; i <= y; ++i) { a[i] = a[i] + k; sum[belong[i]] = (sum[belong[i]] + k) % mod; }
for (int i = belong[x] + 1; i < belong[y]; ++i) { tag[i] += k; tag[i] %= mod; sum[i] = (sum[i] + k * len[i]) % mod; }
}
}
void mu(int x, int y, int k) {
if (belong[x] == belong[y]) {
pushdown(belong[x]);
for (int i = x; i <= y; ++i) { sum[belong[i]] = (sum[belong[i]] + (k - 1) * a[i]) % mod; a[i] = a[i] * k; }
}
else {
pushdown(belong[x]);
for (int i = x; i <= r[belong[x]]; ++i) { sum[belong[i]] = (sum[belong[i]] + (k - 1) * a[i]) % mod; a[i] = a[i] * k;}
pushdown(belong[y]);
for (int i = l[belong[y]]; i <= y; ++i) { sum[belong[i]] = (sum[belong[i]] + (k - 1) * a[i]) % mod; a[i] = a[i] * k;}
for (int i = belong[x] + 1; i < belong[y]; ++i) {
mul[i] = mul[i] * k % mod;
tag[i] = tag[i] * k % mod;
sum[i] = sum[i] * k % mod;
}
}
}
void summ(int x, int y) {
ll ans = 0;
if (belong[x] == belong[y]) {
for (int i = x; i <= y; ++i) ans += (a[i] % mod * mul[belong[i]] % mod + tag[belong[i]]) % mod;
}
else {
for (int i = x; i <= r[belong[x]]; ++i)
{ans += (a[i] * mul[belong[i]] + tag[belong[i]]) % mod;}
for (int i = l[belong[y]]; i <= y; ++i)
{ans += (a[i] * mul[belong[i]]+ tag[belong[i]]) % mod;}
for (int i = belong[x] + 1; i < belong[y]; ++i)
ans = (ans+sum[i]) % mod;
}
ans = (ans + mod) % mod;
printf("%lld\n", ans);
}
int main()
{
for (int i = 1; i <= maxn; ++i) mul[i] = 1;
n = read(), m = read(), mod = read();
for (int i = 1; i <= n; ++i) a[i]=read();
build();
for (int i = 1; i <= m; ++i) {
int t;
int x, y, k;
t=read();
if (t == 2) {
x = read(), y = read(), k = read();
add(x, y, k);//题上说是整数,所以大概可能为负
}
else if(t == 3) {
x = read(), y = read();
summ(x, y);
}
else {
x = read(), y = read(), k = read();
mu(x, y, k);
}
}
return 0;
}