P2023 [AHOI2009]维护序列 - 线段树区间乘法加法
Posted zolrk
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2023 [AHOI2009]维护序列 - 线段树区间乘法加法相关的知识,希望对你有一定的参考价值。
记得及时更新sum(每次修改都更新),写成一个update函数比较好,因为很多时候会忘了%
还有懒标记是标记在这个点本身上的
然后就是左儿子和右儿子一定要看清楚。。。
一个是n * 2 ,一个是 n * 2 + 1 ,涉及到这部分的代码一定要专注
乘法标记优先级大于加法,并且对加法标记也有作用
若要增加加法标记,先让乘法标记作用一下加法标记,再增加加法标记
然后注意乘法标记要初始化为乘法单位元,就是1
每次清空也要初始化为1,建树的时候注意初始化乘法标记
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 100000 + 10;
typedef long long ll;
int n,m,p,a[MAXN];
struct segment{
ll mul, add, sum, siz;
}tr[MAXN*4];
void update(int now) {
tr[now].sum = tr[now*2].sum + tr[now*2+1].sum;
tr[now].sum %= p;
}
void build(int now, int l, int r) {
tr[now].mul = 1;
if(l == r) {
tr[now].siz = 1;
tr[now].sum = a[l];
return;
}
int mid = l + r >> 1;
build(now*2, l, mid);
build(now*2+1, mid+1, r);
tr[now].sum = tr[now*2].sum + tr[now*2+1].sum;
tr[now].sum %= p;
tr[now].siz = tr[now*2].siz + tr[now*2+1].siz;
}
void down(int now) {
int mul = tr[now].mul;
int add = tr[now].add;
tr[now*2].sum *= mul;
tr[now*2].sum %= p;
tr[now*2].sum += add * tr[now*2].siz;
tr[now*2].sum %= p;
tr[now*2+1].sum *= mul;
tr[now*2+1].sum %= p;
tr[now*2+1].sum += add * tr[now*2+1].siz;
tr[now*2+1].sum %= p;
tr[now*2].mul *= mul;
tr[now*2].add *= mul;
tr[now*2].add += add;
tr[now*2].mul %= p;
tr[now*2].add %= p;
tr[now*2+1].mul *= mul;
tr[now*2+1].add *= mul;
tr[now*2+1].add += add;
tr[now*2+1].mul %= p;
tr[now*2+1].add %= p;
tr[now].mul = 1;
tr[now].add = 0;
}
void mul_modi(int now, int l, int r, int x, int y, int k) {
if(x <= l && r <= y) {
tr[now].sum *= k;
tr[now].sum %= p;
tr[now].mul *= k;
tr[now].mul %= p;
tr[now].add *= k;
tr[now].add %= p;
return;
}
down(now);
int mid = l + r >> 1;
if(x <= mid)
mul_modi(now*2, l, mid, x, y, k);
if(y > mid)
mul_modi(now*2+1, mid+1, r, x, y, k);
update(now);
}
void add_modi(int now, int l, int r, int x, int y, int k){
if(x <= l && r <= y) {
tr[now].sum += k * tr[now].siz;
tr[now].sum %= p;
tr[now].add += k;
tr[now].add %= p;
return;
}
down(now);
int mid = l + r >> 1;
if(x <= mid)
add_modi(now*2, l, mid, x, y, k);
if(y > mid)
add_modi(now*2+1, mid+1, r, x, y, k);
update(now);
}
ll query(int now, int l, int r, int x, int y) {
if(x <= l && r <= y) {
return tr[now].sum;
}
down(now);
int mid = l + r >> 1;
ll sum = 0;
if(x <= mid) {
sum += query(now*2, l, mid, x, y);
sum %= p;
}
if(y > mid) {
sum += query(now*2+1, mid+1, r, x, y);
sum %= p;
}
return sum;
}
int main() {
scanf("%d%d", &n, &p);
for(int i=1; i<=n; i++) {
scanf("%d", &a[i]);
}
build(1, 1, n);
scanf("%d", &m);
for(int i=1; i<=m; i++) {
int cmd, x, y, c;
scanf("%d", &cmd);
if(cmd == 1) {//mul
scanf("%d%d%d", &x, &y, &c);
mul_modi(1, 1, n, x, y, c);
} else if(cmd == 2) {
scanf("%d%d%d", &x, &y, &c);
add_modi(1, 1, n, x, y, c);
} else {
scanf("%d%d", &x, &y);
printf("%lld
", query(1, 1, n, x, y));
}
}
return 0;
}
以上是关于P2023 [AHOI2009]维护序列 - 线段树区间乘法加法的主要内容,如果未能解决你的问题,请参考以下文章
P2023 [AHOI2009]维护序列 (线段树区间修改查询)
P2023 [AHOI2009]维护序列 - 线段树区间乘法加法