【模板】线段树 2
题目描述
如题,已知一个数列,你需要进行下面三种操作:
- 将某区间每一个数乘上 x x x;
- 将某区间每一个数加上 x x x;
- 求出某区间每一个数的和。
输入格式
第一行包含三个整数 n , q , m n,q,m n,q,m,分别表示该数列数字的个数、操作的总个数和模数。
第二行包含 n n n 个用空格分隔的整数,其中第 i i i 个数字表示数列第 i i i 项的初始值。
接下来 q q q 行每行包含若干个整数,表示一个操作,具体如下:
操作
1
1
1: 格式:1 x y k
含义:将区间
[
x
,
y
]
[x,y]
[x,y] 内每个数乘上
k
k
k
操作
2
2
2: 格式:2 x y k
含义:将区间
[
x
,
y
]
[x,y]
[x,y] 内每个数加上
k
k
k
操作
3
3
3: 格式:3 x y
含义:输出区间
[
x
,
y
]
[x,y]
[x,y] 内每个数的和对
m
m
m 取模所得的结果
输出格式
输出包含若干行整数,即为所有操作 3 3 3 的结果。
样例 #1
样例输入 #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\%
30% 的数据:
n
≤
8
n \le 8
n≤8,
q
≤
10
q \le 10
q≤10。
对于
70
%
70\%
70% 的数据:$n \le 10^3
,
,
,q \le 10^4$。
对于
100
%
100\%
100% 的数据:
1
≤
n
≤
1
0
5
1 \le n \le 10^5
1≤n≤105,
1
≤
q
≤
1
0
5
1 \le q \le 10^5
1≤q≤105。
除样例外, m = 571373 m = 571373 m=571373。
(数据已经过加强 _)
样例说明:
故输出应为 17 17 17、 2 2 2( 40 m o d 38 = 2 40 \bmod 38 = 2 40mod38=2)。
AC代码
注意有加法懒惰标记plz,乘法标记mlz。
每次加法只更新plz,而乘法要更新mlz和plz。
父类的
m
l
z
=
k
1
,
p
l
z
=
k
2
父类的mlz=k_1,plz=k_2
父类的mlz=k1,plz=k2,左右儿子节点有:
m
l
z
=
m
l
z
∗
k
1
p
l
z
=
p
l
z
∗
k
1
+
k
2
mlz=mlz*k_1\\plz=plz*k_1+k_2
mlz=mlz∗k1plz=plz∗k1+k2
#include <bits/stdc++.h>
#define ll long long
#define ls (i<<1)
#define rs (i<<1|1)
#define rep(i,a,n) for(int i=a;i<n;i++)
const int M = 100001;
template <typename T>
inline void in(T &x){
x=0;
int f=0;char c=getchar();
for(;!isdigit(c);c=getchar()){ f |= c == '-';}
for(;isdigit(c);c=getchar()){x=(x<<3)+(x<<1)+(c^48);}
if(f)x=-x;
}
template <typename T>
inline void out(T x){
if(x<0)putchar('-'),x=-x;
if(x>9)out(x/10);
putchar(x%10+'0');
}
int n,q,m,p,l,r,k;
int a[M]={0};
struct node{
int l;
int r;
ll sum;
ll mlz;
ll plz;
node():sum(0),plz(0),mlz(1){}
}tr[(1<<18)-1];
inline void pushdown(int i){
if(tr[i].mlz!=1||tr[i].plz!=0){
ll k1=tr[i].mlz,k2=tr[i].plz;
tr[ls].sum=(tr[ls].sum*k1%m + (tr[ls].r-tr[ls].l+1)*k2%m)%m;
tr[rs].sum=(tr[rs].sum*k1%m + (tr[rs].r-tr[rs].l+1)*k2%m)%m;
tr[ls].plz=(tr[ls].plz*k1+k2)%m;
tr[rs].plz=(tr[rs].plz*k1+k2)%m;
tr[ls].mlz=tr[ls].mlz*k1%m;
tr[rs].mlz=tr[rs].mlz*k1%m;
tr[i].plz=0;tr[i].mlz=1;
}
}
inline void build(int i,int L,int R){
tr[i].l=L;tr[i].r=R;
if(L==R){
tr[i].sum = a[L-1];
return;
}
int mid = (L+R)>>1;
build(ls,L,mid);
build(rs,mid+1,R);
tr[i].sum = tr[ls].sum + tr[rs].sum;
}
inline void update_add(int i,int L,int R,int k){
if(tr[i].l>=L&&tr[i].r<=R){
tr[i].sum=(tr[i].sum + (tr[i].r-tr[i].l+1)*k%m)%m;
tr[i].plz += k;
return;
}
pushdown(i);
if(tr[ls].r>=L)update_add(ls,L,R,k);
if(tr[rs].l<=R)update_add(rs,L,R,k);
tr[i].sum = tr[ls].sum + tr[rs].sum;
}
inline void update_mul(int i,int L,int R,int k){
if(tr[i].l>=L&&tr[i].r<=R){
tr[i].sum = tr[i].sum*k%m;
tr[i].plz = tr[i].plz*k%m;
tr[i].mlz = tr[i].mlz*k%m;
return;
}
pushdown(i);
if(tr[ls].r>=L)update_mul(ls,L,R,k);
if(tr[rs].l<=R)update_mul(rs,L,R,k);
tr[i].sum = tr[ls].sum + tr[rs].sum;
}
inline ll query(int i,int L,int R){
if(tr[i].l>=L&&tr[i].r<=R)return tr[i].sum;
if(tr[i].l>R||tr[i].r<L)return 0;
pushdown(i);
ll res = 0;
if(tr[ls].r>=L)res = (res+query(ls,L,R))%m;
if(tr[rs].l<=R)res = (res+query(rs,L,R))%m;
return res;
}
int main(){
in(n);in(q);in(m);
rep(i,0,n)in(a[i]);
build(1,1,n);
while(q--){
in(p);in(l),in(r);
if(p==3){
out(query(1,l,r));
putchar('\n');
}
else if(p==1){
in(k);update_mul(1,l,r,k);
}
else{
in(k);update_add(1,l,r,k);
}
}
return 0;
}