有 行询问,每行输入四个数字 、、、,以空格隔开。
若 ,表示将位于 的之间的数字都加 。
若 ,表示将位于 的之间的数字都乘 。
若 ,表示询问 的值 ( 和 忽略)。要输出非负的余数值。
考虑如何处理区间乘。
某些群众:我们可以再打个懒标记 呀!
那如何处理区间求和呢?
在打乘法懒标记的时候,我们可以将原来的 懒标记同时乘上 。操作这段区间时下放一下就行了。
如何下放呢?
下放时我们优先下放 ,然后再下放 。
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+7,mod=10007;
#define int long long
int a[N],id[N],mul[N],add[N],n,len;
void reset(int bid){//下放懒标记
for(int i=(bid-1)*len+1;i<=min(bid*len,n);i++){
a[i]=((1ll*a[i]*mul[bid])%mod+add[bid]+mod)%mod;
}//先下放乘,然后加
add[bid]=0;
mul[bid]=1;
}
void Add(int opt,int l,int r,int c){
c%=mod;
if(id[l]==id[r]){
reset(id[l]);
for(int i=l;i<=r;i++){
if(!opt)a[i]=((a[i]+c)%mod+mod)%mod;
else a[i]=((1ll*a[i]*c%mod)+mod)%mod;
}
return;
}
reset(id[l]);
reset(id[r]);
for(int i=l;id[l]==id[i];i++){
if(!opt)a[i]=((a[i]+c)%mod+mod)%mod;
else a[i]=((1ll*a[i]*c%mod)+mod)%mod;
}
for(int i=id[l]+1;i<id[r];i++){
if(!opt)add[i]=(add[i]+c)%mod;
else mul[i]=mul[i]*1ll*c%mod,add[i]=add[i]*1ll*c%mod;
}//add一起乘
for(int i=r;id[i]==id[r];i--){
if(!opt)a[i]=((a[i]+c)%mod+mod)%mod;
else a[i]=((1ll*a[i]*c%mod)+mod)%mod;
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
len=sqrt(n);
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]%=mod;
id[i]=(i-1)/len+1;
}
for(int i=1;i<=n;i++)mul[i]=1;
for(int i=1;i<=n;i++){
int opt,l,r,c;
cin>>opt>>l>>r>>c;
if(opt<2)Add(opt,l,r,c);
else{
cout<<((a[r]*mul[id[r]]%mod+ add[id[r]])%mod+mod)%mod<<'\n';
}
}
}
暂无评论