题目描述
如题,已知一个数列,你需要进行下面三种操作:
1.将某区间每一个数乘上x
2.将某区间每一个数加上x
3.求出某区间每一个数的和
输入输出格式
输入格式:
第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含3或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k
操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k
操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果
输出格式:
输出包含若干行整数,即为所有操作3的结果。
输入输出样例
说明
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=1000,M<=10000
对于100%的数据:N<=100000,M<=100000
(数据已经过加强^_^)
样例说明:
故输出应为17、2(40 mod 38=2)
首先是乘法和加法都是不受%运算位置影响的,也就是说可以在过程中取模和在最后取模效果相同,不过在过程中取模能把数值控制在0~P-1的范围内
这里对于线段树的操作与之前有所不同
对于当前所给的乘法和加法标记,我们考虑在pushdown的时候先下推乘法标记,如果此时子节点已经有了加法和乘法标记,此时我们需要把乘法标记和加法标记都乘上此标记,
因为之前给的加法标记也会受到影响,然后对于子节点做一个更新。
如果是下推加法标记,此时则对乘法标记不会有影响,直接让加法标记加上对应的值即可。
我们在add的时候也是与pushdown类似
#include<cstdio> #define ls x<<1 #define rs x<<1|1 typedef long long ll; const ll N=100005; ll tr[N<<2],lz1[N<<2],lz2[N<<2],bh,ql,qr,a,p; void bt(ll x,ll l,ll r) { if(l==r) scanf("%lld",&tr[x]); else { ll mid=(l+r)>>1; bt(ls,l,mid); bt(rs,mid+1,r); tr[x]=tr[ls]+tr[rs]; } } void pd(ll x,ll l,ll r,ll mid) { if(lz1[x]!=1) { lz1[ls]=lz1[ls]*lz1[x]%p;//对于左右儿子分别下推乘法标记 lz2[ls]=lz2[ls]*lz1[x]%p; tr[ls]=tr[ls]*lz1[x]%p; lz1[rs]=lz1[rs]*lz1[x]%p; lz2[rs]=lz2[rs]*lz1[x]%p; tr[rs]=tr[rs]*lz1[x]%p; lz1[x]=1; } if(lz2[x]) { lz2[ls]=(lz2[ls]+lz2[x])%p; tr[ls]=(lz2[x]*(mid-l+1)+tr[ls])%p; lz2[rs]=(lz2[rs]+lz2[x])%p; tr[rs]=(lz2[x]*(r-mid)+tr[rs])%p; lz2[x]=0; } } void add(ll x,ll l,ll r) { if(ql<=l&&qr>=r) { if(bh==1) { lz1[x]=lz1[x]*a%p; lz2[x]=lz2[x]*a%p; tr[x]=tr[x]*a%p;//给这区间添加乘法标记时也要给加法标记乘上此数 } else { lz2[x]=(lz2[x]+a)%p; tr[x]=(a*(r-l+1)+tr[x])%p; } } else { ll mid=(l+r)>>1; pd(x,l,r,mid); if(ql<=mid) add(ls,l,mid); if(mid<qr) add(rs,mid+1,r); tr[x]=tr[ls]+tr[rs]; } } ll ask(ll x,ll l,ll r) { if(ql<=l&&qr>=r) return tr[x]; else { ll mid=(l+r)>>1,re=0; pd(x,l,r,mid); if(ql<=mid) re=(re+ask(ls,l,mid))%p; if(mid<qr) re=(re+ask(rs,mid+1,r))%p; return re; } } int main() { ll n,m; scanf("%lld%lld%lld",&n,&m,&p); for(ll i=1;i<N<<2;++i) lz1[i]=1;//为了应对可能出现的乘0情况,要先把乘法标记都变为1 bt(1,1,n); while(m--) { scanf("%lld%lld%lld",&bh,&ql,&qr); if(bh==3) printf("%lld\n",ask(1,1,n)); else { scanf("%lld",&a); add(1,1,n); } } return 0; }