主要是操作三,怎么计算
那么只需要维护区间和和区间平方和即可,1/2用逆元
多个标记注意标记之间有没有影响,mod其实很简单的,但是我标记没处理好一直wa,mod乱搞一下,我mod很丑
#include<iostream>
#include<algorithm>
#include<vector>
#define INF (1ll<<60)
using namespace std;
typedef long long ll;
const int N=1e5+9;
ll a[N];
ll n,m,mod;
struct node{ll val,pfval,mul,add;
}seg[N<<2];
ll tl(ll x){return x<<1;
}
ll tr(ll x){return x<<1|1;
}
ll qmi(ll a,ll b){ll res=1;while(b){if(b&1){res=res*a%mod;}b>>=1;a=a*a%mod;}return res%mod;
}
ll inv(ll x){return qmi(x,mod-2)%mod;
}
void pushup(int id){seg[id].val=(seg[tl(id)].val%mod)+(seg[tr(id)].val%mod);seg[id].pfval=(seg[tl(id)].pfval%mod)+(seg[tr(id)].pfval%mod);
}
void build(int id,int l,int r){seg[id].mul=1;seg[id].add=0;if(l==r){seg[id].val=a[l]%mod;seg[id].pfval=a[l]*a[l]%mod;}else{int mid=(l+r)>>1;build(tl(id),l,mid);build(tr(id),mid+1,r);pushup(id);}
}
bool inrange(int L,int R,int l,int r){return L>=l && R<=r;
}
bool outofrange(int L,int R,int l,int r){return L>r || l>R;
}
void maketag(int id,int l,int r,ll v,int opt){if(opt==1){v%=mod;seg[id].val*=v;seg[id].val%=mod;seg[id].mul*=v;seg[id].mul%=mod;v=(v%mod)*v%mod;seg[id].pfval*=v;(seg[id].add*=v)%=mod;seg[id].pfval%=mod;}else{v%=mod;seg[id].pfval+=((v%mod)*v%mod)*(r-l+1)%mod+2*(v%mod)*(seg[id].val%mod);seg[id].pfval%=mod;seg[id].val+=(r-l+1)*(v%mod); seg[id].val%=mod;seg[id].add+=v;seg[id].add%=mod;}
}
void pushdown(int id,int l,int r){int mid=(l+r)>>1;if(seg[id].mul!=1){maketag(tl(id),l,mid,seg[id].mul,1);maketag(tr(id),mid+1,r,seg[id].mul,1);}if(seg[id].add){maketag(tl(id),l,mid,seg[id].add,2);maketag(tr(id),mid+1,r,seg[id].add,2);}seg[id].mul=1;seg[id].add=0;
}
ll querysum(int id,int L,int R,int l,int r){if(inrange(L,R,l,r)){return seg[id].val%mod;}else if(!outofrange(L,R,l,r)){int mid=(L+R)>>1;pushdown(id,L,R);return querysum(tl(id),L,mid,l,r)%mod+querysum(tr(id),mid+1,R,l,r)%mod;}else{return 0;}
}
ll querypfsum(int id,int L,int R,int l,int r){if(inrange(L,R,l,r)){return seg[id].pfval%mod;}else if(!outofrange(L,R,l,r)){int mid=(L+R)>>1;pushdown(id,L,R);return querypfsum(tl(id),L,mid,l,r)%mod+querypfsum(tr(id),mid+1,R,l,r)%mod;}else{return 0;}
}
void modifymul(int id,int L,int R,int l,int r,ll v){if(inrange(L,R,l,r)){maketag(id,L,R,v,1);}else if(!outofrange(L,R,l,r)){int mid=(L+R)>>1;pushdown(id,L,R);modifymul(tl(id),L,mid,l,r,v);modifymul(tr(id),mid+1,R,l,r,v);pushup(id);}
}
void modifyadd(int id,int L,int R,int l,int r,ll v){if(inrange(L,R,l,r)){maketag(id,L,R,v,2);}else if(!outofrange(L,R,l,r)){int mid=(L+R)>>1;pushdown(id,L,R);modifyadd(tl(id),L,mid,l,r,v);modifyadd(tr(id),mid+1,R,l,r,v);pushup(id);}
}
void solve(){cin>>n>>m>>mod;for(int i=1;i<=n;i++){cin>>a[i];a[i]%=mod;}build(1,1,n);for(int i=1;i<=m;i++){int opt;cin>>opt;if(opt==1){int l,r,v;cin>>l>>r>>v;modifyadd(1,1,n,l,r,v);}else if(opt==2){int l,r,v;cin>>l>>r>>v;modifymul(1,1,n,l,r,v);}else{int l,r;cin>>l>>r;ll res1=querysum(1,1,n,l,r)%mod;res1=res1*res1%mod;ll res2=querypfsum(1,1,n,l,r)%mod;res2%=mod;ll ans=(((res1-res2)%mod+mod)%mod)*inv(2)%mod;cout<<ans%mod<<'\n';}}
}
int main(){ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);int t;cin>>t;while(t--){solve();}return 0;
}