题意: 给一个数组, 有三个操作
1. 区间乘法
2. 区间加法
3. 询问区间的和并取模。
思路:两个数组作为懒惰标记。分别是对加法和乘法的对子树传递的保存。每次乘法时, 都要把sum数组也乘起来,在向下传递时就可以先乘法再加法,注意记录下一子树sum和mul的数值的更新。
#include <bits/stdc++.h>
#define lk k<<1
#define rk k<<1|1
using namespace std;
const int MAXN = 100005;
const int mod = 1e9+7;
typedef long long LL;
struct T
{
int l, r;
LL c;
} tree[MAXN<<2];
LL add[MAXN<<2], mul[MAXN<<2];
void pushdown(int k, int d,int p)
{
if(mul[k]==1&&add[k]==0)
return ;
tree[k<<1].c=tree[k<<1].c*mul[k]%p;
tree[k<<1|1].c=tree[k<<1|1].c*mul[k]%p;
tree[k<<1].c=(tree[k<<1].c+add[k]*(d-(d>>1)))%p;
tree[k<<1|1].c=(tree[k<<1|1].c+add[k]*(d>>1))%p;
mul[k<<1]=mul[k]*mul[k<<1]%p;
mul[k<<1|1]=mul[k]*mul[k<<1|1]%p;
add[k<<1]=(add[k<<1]*mul[k]+add[k])%p;
add[k<<1|1]=(add[k]+add[k<<1|1]*mul[k])%p;
add[k]=0;
mul[k]=1;
return ;
}
void pushup(int k,int p)
{
tree[k].c=(tree[k<<1].c+tree[k<<1|1].c)%p;
}
void build(int l, int r, int k, int p)
{
tree[k].l=l;
tree[k].r=r;
tree[k].c=0;
mul[k]=1;
add[k]=0;
if(l==r)
{
scanf("%lld", &tree[k].c);
return;
}
int mid=(tree[k].l+tree[k].r)>>1;
build(l, mid, k<<1, p);
build(mid+1,r,k<<1|1, p);
pushup(k, p);
}
void update(int l, int r, int k, LL c, int op, int p)
{
if(tree[k].l>=l&&tree[k].r<=r){
if(op==1){
add[k]=add[k]*c%p;
mul[k]=mul[k]*c%p;
tree[k].c=tree[k].c*c%p;
}
else{
add[k]=(add[k]+c)%p;
tree[k].c=(tree[k].c+(tree[k].r-tree[k].l+1)*c)%p;
}
return;
}
pushdown(k, tree[k].r-tree[k].l+1, p);
int mid=(tree[k].l+tree[k].r)>>1;
if(l<=mid)
update(l,r,k<<1,c,op,p);
if(r>mid)
update(l,r,k<<1|1,c,op,p);
pushup(k,p);
}
LL query(int l, int r, int k, int p)
{
if(tree[k].l>=l&&tree[k].r<=r)
return tree[k].c%p;
pushdown(k, tree[k].r-tree[k].l+1, p);
LL ans=0;
int mid = (tree[k].l+tree[k].r)>>1;
if(l<=mid)
ans=(ans+query(l,r,k<<1,p))%p;
if(r>mid)
ans=(ans+query(l,r,k<<1|1, p))%p;
//pushup(k, p);
return ans%p;
}
int main()
{
int n, m, p;
while(~scanf("%d %d", &n,&p))
{
build(1, n, 1, p);
scanf("%d", &m);
while(m--)
{
int op,l,r;
LL v;
scanf("%d %d %d", &op, &l, &r);
if(op==1||op==2)
{
scanf("%lld", &v);
update(l, r, 1, v, op, p);
}
else
{
printf("%lld\n", query(l, r, 1, p));
}
}
}
return 0;
}