我永远喜欢奈芙莲.jpg
分析:
数论数学和数据结构完美的融合。
通过支持区间加的线段树维护每个位置的数,可以通过标记永久化显著减小常数。
使用扩展欧拉定理降幂,这样对于每个操作只需进行log次降幂即可将模数降为1。
注意边界处理。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN=500005;
inline LL read(){
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
int n,m,prm[20000005>>3],phi[20000005],cnt,loc,ql,qr;
LL a[MAXN],sum[MAXN<<2],add[MAXN<<2],k;
bool vis[20000005];
void pre_process(){
n=20000000;
phi[1]=1;
for(register int i=2;i<=n;i++){
if(!vis[i]){
prm[++cnt]=i;
phi[i]=i-1;
}
for(register int j=1;j<=cnt&&i*prm[j]<=n;j++){
vis[i*prm[j]]=1;
if(i%prm[j]==0){
phi[i*prm[j]]=phi[i]*prm[j];
break;
}
phi[i*prm[j]]=phi[i]*(prm[j]-1);
}
}
}
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc ((o<<1)|1)
void build(int o,int l,int r){
if(l==r){
sum[o]=a[l];
return;
}
build(lc,l,mid);
build(rc,mid+1,r);
}
void upd(int o,int l,int r){
if(l==r) sum[o]+=k;
if(ql<=l&&r<=qr){
add[o]+=k;
return;
}
if(mid>=ql) upd(lc,l,mid);
if(mid<qr) upd(rc,mid+1,r);
}
LL query(int o,int l,int r){
if(l==r&&l==loc) return sum[o];
if(loc<=mid) return query(lc,l,mid)+add[o];
else return query(rc,mid+1,r)+add[o];
}
#undef mid
#undef lc
#undef rc
LL Qpow(LL x,LL y,LL p){
LL ans=1,t=x;bool flag=0,tflag=0;
if(t>=p) tflag=1,t%=p;
while(y){
if(y&1){
ans*=t;
if(tflag) flag=1;
if(ans>=p) flag=1,ans%=p;
}
t*=t;
if(t>=p) tflag=1,t%=p;
y>>=1;
}
return flag==1?-ans:ans;
}//返回负数表示取模过
LL solve(int l,LL p){
if(p==1) return 0;
loc=l;LL cur=query(1,1,n);
if(l==qr) return cur>=p?-cur%p:cur;
LL tim=solve(l+1,phi[p]);
if(tim<=0) tim=-tim+phi[p];//返回非正数表示tim需要+phi[p]
return Qpow(cur,tim,p)%p;//负数取模还是负数
}
int main(){
pre_process();
n=read(),m=read();
for(int i=1;i<=n;i++) a[i]=read();
build(1,1,n);
while(m--){
int opt=read();
if(opt==1){
ql=read(),qr=read(),k=read();
upd(1,1,n);
}
else{
ql=read(),qr=read(),k=read();
printf("%lld\n",abs(solve(ql,k)%k));//同
}
}
return 0;
}