好题啊!
调了一个中午,发现有一条语句 (RE) 了。在 (windows) 下没关系,(linux) 下有问题,大大的问题。
while(phi[tot]!=1) phi[++tot]=calc_phi(phi[tot-1]);
算是拓展欧拉定理的题吧。线段树只是一个工具,最主要还是暴力修改。因为 (varphi) 不断套下去最多会有 (lfloor log n floor) 层,所以我们对于每一层暴力算一遍,加上快速幂,时间复杂度 (O(nlog^3 n)),显然可能被卡。怎么优化呢?
将 (O(log n)) 的快速幂换成 (O(1)) 的快速幂就好了,时间复杂度 (O(nlog^2 n))
(Code Below:)
#include <bits/stdc++.h>
#define int long long
#define lson (rt<<1)
#define rson (rt<<1|1)
using namespace std;
const int maxn=100000+10;
const int base=(1<<14)-1;
int n,m,p,c,a[maxn],sum[maxn<<2],Min[maxn<<2],pw1[55][maxn],pw2[55][maxn],phi[maxn],tot;
bool b1[55][maxn],b2[55][maxn],flag;
inline int read(){
register int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return (f==1)?x:-x;
}
int calc_phi(int n){
int ans=n,m=sqrt(n);
for(int i=2;i<=m;i++){
if(n%i==0){
ans=ans/i*(i-1);
while(n%i==0) n/=i;
}
}
if(n>1) ans=ans/n*(n-1);
return ans;
}
void pre(){
int tmp=p;phi[0]=p;
while(tmp!=1) tmp=calc_phi(tmp),phi[++tot]=tmp;
phi[++tot]=1;
for(int i=0;i<=tot;i++){
pw1[i][0]=1;
for(int j=1;j<=base+1;j++){
pw1[i][j]=pw1[i][j-1]*c;
if(pw1[i][j]>=phi[i]) b1[i][j]=1,pw1[i][j]%=phi[i];
b1[i][j]|=b1[i][j-1];
}
}
for(int i=0;i<=tot;i++){
pw2[i][0]=1;
b2[i][1]=b1[i][base+1];
for(int j=1;j<=base;j++){
pw2[i][j]=pw2[i][j-1]*pw1[i][base+1];
if(pw2[i][j]>=phi[i]) b2[i][j]=1,pw2[i][j]%=phi[i];
b2[i][j]|=b2[i][j-1];
}
}
}
int calc(int a,int dep){
flag=0;
int x=a&base,y=(a>>14)&base;
int ans=pw1[dep][x]*pw2[dep][y];
if(ans>=phi[dep]) flag=1,ans%=phi[dep];
flag|=b1[dep][x]|b2[dep][y];
return ans;
}
int dfs(int a,int dep,int lim){
flag=0;
if(dep==lim){
if(a>=phi[dep]) flag=1,a%=phi[dep];
return a;
}
int b=dfs(a,dep+1,lim);
return calc(flag?b+phi[dep+1]:b,dep);
}
inline void pushup(int rt){
sum[rt]=(sum[lson]+sum[rson])%p;
Min[rt]=min(Min[lson],Min[rson]);
}
void build(int l,int r,int rt){
if(l == r){
sum[rt]=a[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,lson);
build(mid+1,r,rson);
pushup(rt);
}
void update(int L,int R,int l,int r,int rt){
if(Min[rt]>=tot) return ;
if(l == r){
Min[rt]++;
sum[rt]=dfs(a[l],0,Min[rt]);
return ;
}
int mid=(l+r)>>1;
if(L <= mid) update(L,R,l,mid,lson);
if(R > mid) update(L,R,mid+1,r,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L <= l && r <= R){
return sum[rt];
}
int mid=(l+r)>>1,ans=0;
if(L <= mid) ans=(ans+query(L,R,l,mid,lson))%p;
if(R > mid) ans=(ans+query(L,R,mid+1,r,rson))%p;
return ans;
}
signed main()
{
n=read(),m=read(),p=read(),c=read();
for(int i=1;i<=n;i++) a[i]=read();
pre();build(1,n,1);
int op,l,r;
while(m--){
op=read(),l=read(),r=read();
if(op==0) update(l,r,1,n,1);
if(op==1) printf("%lld
",query(l,r,1,n,1));
}
return 0;
}