【题意】区间内ai修改为c^ai(c为给定的固定数),区间求和
【分析】这道题目需要用到一个扩展欧拉定理,我们发现我们实际上在不断的对幂进行取phi的操作,所以这个数量级降的也是十分快,可以先算出最多经历的次数t对于一个修改操作,如果这个区间的修改次数都多余t了,就不用在进行操作了,否则暴力修改即可
注意讨论这个幂是否大于phi,挺麻烦的,还要一直记录着over
【代码】
#include <bits/stdc++.h> using namespace std; # define Rep(i,a,b) for(int i=a;i<=b;i++) # define _Rep(i,a,b) for(int i=a;i>=b;i--) # define RepG(i,u) for(int i=head[u];~i;i=e[i].next) typedef long long ll; const int N=1e5+5; const int bl=10000; const int M=65; template<typename T> void read(T &x){ x=0;int f=1; char c=getchar(); for(;!isdigit(c);c=getchar())if(c=='-')f=-1; for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0'; x*=f; } # define int long long int n,m,p,c; int a[N]; int phi[N],dep; int qpow[bl+5][M][2]; bool flag,over[bl+5][M][2]; struct segment_tree{ int l,r; int sum,tim; }seg[N<<2]; # define lc (u<<1) # define rc (u<<1|1) int getphi(int x){ int res=x; for(int i=2;1ll*i*i<=x;i++){ if(x%i==0) res=res/i*(i-1); while(x%i==0)x/=i; } if(x>1)res=res/x*(x-1); return res; } void init(){ int x=p; phi[0]=x; while(x>1){ x=getphi(x); phi[++dep]=x; } phi[++dep]=1; Rep(i,0,dep){ qpow[0][i][0]=1; Rep(j,1,bl){ qpow[j][i][0]=qpow[j-1][i][0]*c; if(qpow[j][i][0]>=phi[i])over[j][i][0]=true,qpow[j][i][0]%=phi[i]; over[j][i][0]|=over[j-1][i][0]; } } Rep(i,0,dep){ qpow[0][i][1]=1; Rep(j,1,bl){ qpow[j][i][1]=qpow[j-1][i][1]*qpow[bl][i][0]; if(qpow[j][i][1]>=phi[i])over[j][i][1]=true,qpow[j][i][1]%=phi[i]; over[j][i][1]|=over[j-1][i][1]; } } } int Qpow(int ind,int p){ flag|=over[ind%bl][p][0]|over[ind/bl][p][1]; int res=qpow[ind%bl][p][0]*qpow[ind/bl][p][1]; if(res>=phi[p])flag=true,res%=phi[p]; return res; } int calc(int id,int lim,int d){ flag=false; if(d==lim){ if(a[id]>=phi[d]){ flag=true; return a[id]%phi[d]; } return a[id]; } int x=calc(id,lim,d+1); if(flag)x+=phi[d+1],flag=false; return Qpow(x,d); } void pushup(int u){ seg[u].sum=(seg[lc].sum+seg[rc].sum)%p; seg[u].tim=min(seg[lc].tim,seg[rc].tim); } void build(int u,int l,int r){ seg[u].l=l,seg[u].r=r; if(l==r){ seg[u].sum=a[l]; seg[u].tim=0; return; } int mid=l+r>>1; build(lc,l,mid); build(rc,mid+1,r); pushup(u); } void update(int u,int l,int r){ if(seg[u].tim>=dep)return; if(seg[u].l==seg[u].r){ seg[u].tim++; seg[u].sum=calc(seg[u].l,seg[u].tim,0); return; } int mid=seg[u].l+seg[u].r>>1; if(l<=mid)update(lc,l,r); if(r>mid)update(rc,l,r); pushup(u); } int query(int u,int l,int r){ if(seg[u].l>=l&&seg[u].r<=r)return seg[u].sum; int mid=seg[u].l+seg[u].r>>1; int res=0; if(l<=mid)res+=query(lc,l,r); if(r>mid)res+=query(rc,l,r); res%=p; return res; } signed main() { freopen("greet.in","r",stdin); freopen("greet.out","w",stdout); read(n),read(m),read(p),read(c); Rep(i,1,n)read(a[i]); init(); build(1,1,n); Rep(i,1,m){ int opt,x,y; read(opt),read(x),read(y); if(!opt)update(1,x,y); else printf("%lld\n",query(1,x,y)); } return 0; }