传送门
那场WA了12发还是过不去.主要是区间赋值的操作想复杂了.分享一下遇到的问题.
考虑题目给的几个操作:
1.区间加 区间乘 这两个没什么难度,乘的时候把块里面加法标记也乘一下就好了.
2 区间赋值 这个其实可以用上面两个操作推导出来,不要多加一个标记去记录(速度会慢而且增大代码难度).可以乘0再加x就ok了.
3 增加一个x在尾部.这个操作可能会使最后一个块的大小太大.所以可以在这个操作超过sqrt(n)的时候重构一下块.这个次数一次是O(n)的.而且不会超过sqrt(n)次.
复杂度方面块取sqrt(n)的话总体就是O(nsqrt(n))的.题目给了3s.所以勉勉强强够用.要注意减少取模运算.两个intmax乘起来是不会爆longlongmax的.所以可以在中间的时候不取模.
代码
#pragma GCC optimize(2)
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=b;++i)
#define afir(i,a,b) for(int i=a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
inline LL read(){
LL x = 0,f=1;char ch = getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,blo,num,mod,pos[N];
LL L[N],R[N],sum[N],add[N],mul[N],a[N];
void clr(int i){
fir(j,L[i],R[i]) a[j] = (a[j]*mul[i]+ add[i])%mod;
sum[i] = (sum[i]*mul[i]+(R[i]-L[i]+1)*add[i])%mod;
add[i] = 0;mul[i] = 1;
}
bool f = 0;
void build(){
if(f){
fir(i,1,num){
clr(i);
}
}
blo = sqrt(n);
num = n/blo;
fir(i,1,num){
L[i] = (i-1)*blo+1;
R[i] = i*blo;
}
if(n % blo){
num++;
L[num] = R[num-1]+1;
R[num] = n;
}
if(!f){
f = 1;
fir(i,1,N-1) add[i] = 0,sum[i] = 0,mul[i] = 1;
fir(i,1,num){
sum[i] = 0;add[i] = 0;mul[i] = 1;
fir(j,L[i],R[i]){
sum[i] = (sum[i] + a[j])%mod;
pos[j] = i;
}
}
return;
}
fir(i,1,num){
sum[i] = 0;add[i] = 0;mul[i] = 1;
fir(j,L[i],R[i]){
sum[i] = (sum[i] + a[j])%mod;
pos[j] = i;
}
}
}
void Add(int l,int r,LL v){
int p = pos[l],q = pos[r];
if(p == q){
clr(p);
fir(i,l,r) a[i] = (a[i] + v)%mod,sum[p] = (sum[p]+v)%mod;
}
else{
fir(i,p+1,q-1){
add[i] = (add[i] + v)%mod;
}
clr(p);
fir(i,l,R[p]) a[i] = (a[i] + v)%mod;
sum[p] = (sum[p] + (R[p]-l+1)*v)%mod;
clr(q);
fir(i,L[q],r) a[i] = (a[i] + v)%mod;
sum[q] = (sum[q] + (r-L[q]+1)*v)%mod;
}
}
void Mul(int l,int r,LL v){
int p = pos[l],q = pos[r];
if(p == q){
clr(p);
fir(i,l,r){
sum[p] = (sum[p]-a[i]+mod)%mod;
a[i] = a[i]*v%mod;
sum[p] = (sum[p]+a[i])%mod;
}
}
else{
fir(i,p+1,q-1){
mul[i] = (mul[i]*v)%mod,add[i] = add[i]*v%mod;
}
clr(p);
fir(i,l,R[p]){
sum[p] = (sum[p]-a[i]+mod)%mod;
a[i] = a[i]*v%mod;
sum[p] = (sum[p]+a[i])%mod;
}
clr(q);
fir(i,L[q],r){
sum[q] = (sum[q]-a[i]+mod)%mod;
a[i] = a[i]*v%mod;
sum[q] = (sum[q]+a[i])%mod;
}
}
}
LL query(int l,int r){
int p = pos[l],q = pos[r];
LL res = 0;
if(p == q){
clr(p);
fir(i,l,r){
res = (res + a[i])%mod;
}
}
else{
fir(i,p+1,q-1){;
res = (res + sum[i]*mul[i] + (R[i]-L[i]+1)*add[i])%mod;
}
clr(p);
fir(i,l,R[p]){
res = (res + a[i])%mod;
}
clr(q);
fir(i,L[q],r){
res = (res + a[i])%mod;
}
}
return res;
}
int main(){
n = read(); m = read(); mod = read();
fir(i,1,n) a[i] = read();
build();
int cnt = 0;
while(m--){
int op,l,r,x;
cin >> op;
if(op <= 3){
l = read(); r =read(); x= read();
if(op == 1) Add(l,r,x);
else if(op == 2) Mul(l,r,x);
else{
Mul(l,r,0);
Add(l,r,x);
}
}
else if(op == 4){
cnt++;
x = read();
a[++n] = x;
clr(num);
R[num]++;
sum[num] = (sum[num]+x)%mod;
pos[n] = num;
if(cnt > blo){
build();
cnt = 0;
}
}
else{
l = read(); r = read();
printf("%lld\n",query(l,r));
}
}
return 0;
}