终于不对拍1A线段树了、太不容易了
虽然这题挺裸的,省选福利,记住先乘后加的原则就可以搞了
注意位运算和取模的优先级,不要乱了,注意代码的位置问题
码(发现我的线段树非常瘦):
#include<iostream>
#include<cstdio>
using namespace std;
#define zuo o<<1,l,mid
#define you o<<1|1,mid+1,r
#define lnl long long
#define N 100005
lnl v[N<<2],jbj[N<<2],cbj[N<<2],a,b,c,op,wc[N],n,m,P,ans;
void up(int o)
{
v[o]=(v[o<<1]+v[o<<1|1])%P;
}
void down(int o,int l,int r)
{
int ll=(o<<1);
int rr=(o<<1|1);
v[ll]*=cbj[o];
v[rr]*=cbj[o];
v[ll]+=jbj[o]*(((r+l)>>1)-l+1)%P;
v[rr]+=jbj[o]*((r-((r+l)>>1)))%P;
v[ll]%=P;
v[rr]%=P;
jbj[ll]*=cbj[o];
jbj[rr]*=cbj[o];
jbj[ll]+=jbj[o];
jbj[rr]+=jbj[o];
cbj[ll]*=cbj[o];
cbj[rr]*=cbj[o];
cbj[ll]%=P;
cbj[rr]%=P;
jbj[ll]%=P;
jbj[rr]%=P;
cbj[o]=1;
jbj[o]=0;
}
void jian(int o,int l,int r)
{
cbj[o]=1;
if(l==r)
{
v[o]=wc[l];
return ;
}
int mid=(l+r)>>1;
jian(zuo);
jian(you);
up(o);
}
void gai(int o,int l,int r)
{
if(a<=l&&r<=b)
{
if(op==1)
{
v[o]*=c;v[o]%=P;
cbj[o]*=c;
cbj[o]%=P;
jbj[o]*=c;
jbj[o]%=P;
}
if(op==2)
{
v[o]+=c*(r-l+1)%P;v[o]%=P;
jbj[o]+=c;
jbj[o]%=P;
}
if(op==3)
{
ans+=v[o];
ans%=P;
}
return;
}
down(o,l,r);
int mid=(l+r)>>1;
if(a<=mid) gai(zuo);
if(b>mid) gai(you);
up(o);
}
int main()
{
int i;
scanf("%lld%lld",&n,&P);
for(i=1;i<=n;i++)
{
scanf("%lld",&wc[i]);
}
jian(1,1,n);
scanf("%lld",&m);
for(i=1;i<=m;i++)
{
scanf("%lld",&op);
if(op==1||op==2)
{
scanf("%lld%lld%lld",&a,&b,&c);
gai(1,1,n);
}
if(op==3)
{
ans=0;
scanf("%lld%lld",&a,&b);
gai(1,1,n);
printf("%lld\n",ans);
}
}
}