题意
一种序列,三种操作。
1.从t到g 每一个乘c
2.从t到g 每一个加c
3.查询区间和
思路
这一题的变化在于要注意取模。
其次,对于乘和加,需要放置两个标记,下放lazy的时候写成一个pushdown,并且做乘运算的时候,加法lazy也要有相应的改变。还有就是lazy和ans值的改变与传统线段树模板的不同
代码
#include<iostream>
#include<cmath>
#include<stack>
#include<map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define Endl "\n"
typedef long long ll;
const int maxn=1e6;
const int mod=1e9+7;
using namespace std;
ll n,P,M;
int key,t,g,c;
ll ans[maxn<<2];
ll lazyjia[maxn<<2];
ll lazycheng[maxn<<2];
inline ll read()
{
ll x = 0, f = 1; char ch; ch = getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void PushUp(int rt)
{
ans[rt]=(ans[rt<<1]+ans[rt<<1|1])%P;
return ;
}
//建树
void Build(int l,int r,int rt)
{
lazycheng[rt]=1;
// lazyjia[rt]=0;
if (l==r)
{
ans[rt]=read()%P;
return;
}
int mid=(l+r)>>1;
int left=rt<<1;
int right=left|1;
Build(l,mid,left);
Build(mid+1,r,right);
PushUp(rt);
return ;
}
void PushDown(int rt,int ln,int rn)//ln表示左子树元素结点个数,rn表示右子树结点个数
{
if (lazycheng[rt]!=1)
{
ll left=rt<<1;
ll right=left|1;
lazyjia[left]=(lazyjia[left]*lazycheng[rt])%P;
lazyjia[right]=(lazyjia[right]*lazycheng[rt])%P;
lazycheng[left]=(lazycheng[rt]*lazycheng[left])%P;
lazycheng[right]=(lazycheng[rt]*lazycheng[right])%P;
ans[left]=(lazycheng[rt]*ans[left])%P;
ans[right]=(lazycheng[rt]*ans[right])%P;
lazycheng[rt]=1;
// return ;
}
if(lazyjia[rt])
{
ll left=rt<<1;
ll right=left|1;
ans[left]=(ans[left]+lazyjia[rt]*ln)%P;
ans[right]=(ans[right]+lazyjia[rt]*rn)%P;
lazyjia[left]=(lazyjia[left]+lazyjia[rt])%P;
lazyjia[right]=(lazyjia[right]+lazyjia[rt])%P;
lazyjia[rt]=0;
// return ;
}
return ;
}
void add(int L,int R,int C,int l,int r,int rt)
{
if(R<l||L>r)
return ;
if (L<=l&&r<=R)
{
ans[rt]=(ans[rt]+(r-l+1)*C)%P;
lazyjia[rt]=(lazyjia[rt]+C)%P;
// cout<<"ans "<<rt<<" "<<ans[rt]<<Endl;
return;
}
int mid=(l+r)>>1;
int left=rt<<1;
int right=left|1;
PushDown(rt,mid-l+1,r-mid);
if (L<=mid) add(L,R,C,l,mid,left);
if (R>mid) add(L,R,C,mid+1,r,right);
PushUp(rt);
// for(int i=1;i<=13;i++)
// cout<<ans[i]<<" ";
// cout<<Endl;
return ;
}
void multiply(int L,int R,int C,int l,int r,int rt)
{
if(R<l||L>r)
return ;
if (L<=l&&r<=R)
{
ans[rt]=(C*ans[rt])%P;
lazycheng[rt]=(lazycheng[rt]*C)%P;
lazyjia[rt]=(lazyjia[rt]*C)%P;
// cout<<"ans "<<rt<<" "<<ans[rt]<<Endl;
return ;
}
int mid=(l+r)>>1;
int left=rt<<1;
int right=left|1;
PushDown(rt,mid-l+1,r-mid);
if (L<=mid) multiply(L,R,C,l,mid,left);
if (R>mid) multiply(L,R,C,mid+1,r,right);
PushUp(rt);
// for(int i=1;i<=13;i++)
// cout<<ans[i]<<" ";
// cout<<Endl;
return ;
}
ll Query(int L,int R,int l,int r,int rt)
{
if(L>r||R<l)
return 0;
if (L<=l&&r<=R)
return ans[rt];
int mid=(l+r)>>1;
int left=rt<<1;
int right=left|1;
PushDown(rt,mid-l+1,r-mid);//若更新只有点更新,不需要这句
ll ANS=0;
if (L<=mid) ANS+=Query(L,R,l,mid,left)%P;
if (R>mid) ANS+=Query(L,R,mid+1,r,right)%P;
return ANS%P;
}
int main()
{
n=read(),P=read();
Build(1,n,1);
// for(int i=0;i<10;i++)
// cout<<ans[i]<<" ";
M=read();
while(M--)
{
key=read(),t=read(),g=read();
if(key==1)
{
c=read();
multiply(t,g,c,1,n,1);
}
else if(key==2)
{
c=read();
add(t,g,c,1,n,1);
}
else
{
cout<<Query(t,g,1,n,1)%P<<Endl;
}
}
return 0;
}