題目
首先考慮沒有修改的狀況。顯然直接暴力擴展歐拉定理就好了,單次複雜度爲\(O(\log p)\)的。
如今有了修改,咱們能夠樹狀數組維護差分數組,而後\(O(\log n)\)地單次查詢單點值。node
#include<bits/stdc++.h> #define LL long long using namespace std; namespace IO { char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[15],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21); char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);} void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;} void Put(char x){*oS++=x;if(oS==oT)Flush();} int read(){int x=0;char ch=Get();while(ch>57||ch<48)ch=Get();while(ch>=48&&ch<=57)x=x*10+(ch^48),ch=Get();return x;} void write(int x){int top=0;if(x<0)Put('-'),x=-x;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('\n');} } using namespace IO; void max(int &a,int b){a=a>b? a:b;} #define N 500007 #define M 20000007 int n,phi[M],p[M>>3],opt[N],l[N],r[N],P[N]; bitset<M>vis; LL c[N]; void add(int p,int v){while(p<=n)c[p]+=v,p+=p&-p;} LL query(int p){LL v=0;while(p)v+=c[p],p-=p&-p;return v;} void modify(int l,int r,int v){add(l,v),add(r+1,-v);} struct node{LL num;int flg;node(LL Num=0,int Flg=0):num(Num),flg(Flg){}}; node power(LL a,int k,int p) { node ans=node(1,0); if(a>=p) a%=p,ans.flg=1; while(k) { if(k&1) ans.num=ans.num*a; if(ans.num>=p) ans.num%=p,ans.flg=1; a*=a,k>>=1; if(a>=p) a%=p,ans.flg=1; } return ans; } node calc(int l,int r,int p) { LL a=query(l); if(p==1) return node(0,1); if(a==1) return node(1,0); if(l==r) return a<p? node(a,0):node(a%p,1); int Phi=phi[p];node ans=calc(l+1,r,Phi); if(ans.flg) ans.num+=Phi; return power(a,ans.num,p); } int main() { n=read();int Q=read(),i,j,tot=0,Max=0; for(i=1;i<=n;++i) tot=read(),modify(i,i,tot); for(i=1;i<=Q;++i) { opt[i]=read(),l[i]=read(),r[i]=read(),P[i]=read(); if(opt[i]==2) max(Max,P[i]); } for(tot=0,phi[1]=1,i=2;i<=Max;++i) { if(!vis[i]) p[++tot]=i,phi[i]=i-1; for(j=1;i*p[j]<=Max&&j<=tot;++j) { vis[i*p[j]]=1; if(!(i%p[j])){phi[i*p[j]]=phi[i]*p[j];break;} phi[i*p[j]]=phi[i]*(p[j]-1); } } for(i=1;i<=Q;++i)if(opt[i]==1) modify(l[i],r[i],P[i]); else write(calc(l[i],r[i],P[i]).num); return Flush(),0; }