Description
Informatikverbindetdichundmich.
信息将你我连结。B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数。一共有m个操作,可以
分为两种:0 l r表示将第l个到第r个数(al,al+1,...,ar)中的每一个数ai替换为c^ai,即c的ai次方,其中c是
输入的一个常数,也就是执行赋值ai=c^ai1 l r求第l个到第r个数的和,也就是输出:sigma(ai),l<=i<=rai因为
这个结果可能会很大,所以你只需要输出结果mod p的值即可。
Input
第一行有三个整数n,m,p,c,所有整数含义见问题描述。
接下来一行n个整数,表示a数组的初始值。
接下来m行,每行三个整数,其中第一个整数表示了操作的类型。
如果是0的话,表示这是一个修改操作,操作的参数为l,r。
如果是1的话,表示这是一个询问操作,操作的参数为l,r。
1 ≤ n ≤ 50000, 1 ≤ m ≤ 50000, 1 ≤ p ≤ 100000000, 0 < c <p, 0 ≤ ai < p
Output
对于每个询问操作,输出一行,包括一个整数表示答案mod p的值。
Sample Input
4 4 7 2
1 2 3 4
0 1 4
1 2 4
0 1 4
1 1 3
1 2 3 4
0 1 4
1 2 4
0 1 4
1 1 3
Sample Output
0
3
3
HINT
鸣谢多名网友提供正确数据,已重测!
根据欧拉定理,当更新超过一定次数时,phi(p)等于1,不会再改变了,
于是线段树暴力更新,统计节点更新次数,当更新次数大于变成phi(1)=1的个数就不再管它了
1 ************************************************************** 2 Problem: 4869 3 User: white_hat_hacker 4 Language: C++ 5 Result: Accepted 6 Time:24092 ms 7 Memory:2776 kb 8 ****************************************************************/ 9 10 #include<cstdio> 11 #include<cstdlib> 12 #include<algorithm> 13 #include<cstring> 14 #include<vector> 15 #define MAXN 50005 16 #define DEBUG 0 17 #define ll long long 18 using namespace std; 19 int dat[MAXN*4]; 20 int cnt[MAXN*4]; 21 int a[MAXN]; 22 int n,c; 23 int MOD,tot; 24 int phi[MAXN]; 25 int Phi(int x){ 26 int ret=x; 27 for(int i=2;i*i<=x;i++){ 28 if(!(x%i)){ 29 ret/=i;ret*=(i-1); 30 while(!(x%i)){ 31 x/=i; 32 } 33 } 34 } 35 if(x^1){ 36 ret/=x; ret*=(x-1); 37 } 38 return ret; 39 } 40 void work(int x){ 41 phi[tot]=x; 42 tot++; 43 if(1==x){ 44 return ; 45 } 46 work(Phi(x)); 47 } 48 int read(){ 49 int x=0;char ch=getchar(); 50 while(ch<'0'||ch>'9'){ch=getchar();} 51 while(ch>='0'&&c<='9'){x=x*10+ch-'0';ch=getchar();} 52 return x; 53 } 54 int Power(int a,int b,int p){ 55 int ret=1; 56 while(b){ 57 if(b&1){ 58 ret=ret*a%p; 59 } 60 a=a*a%p; 61 b>>=1; 62 } 63 return ret; 64 } 65 int Pow(int a,int b,int p,bool &bi){ 66 int ret=1; 67 bool fx=0; 68 while(b){ 69 if(b&1){ 70 bi|=(fx|(1LL*ret*a>=p)); 71 ret=1LL*ret*a%p; 72 } 73 fx|=(1LL*a*a>=p); 74 a=1LL*a*a%p; 75 b>>=1; 76 } 77 return ret; 78 } 79 int solve(int a,int L){ 80 int ret=a%phi[L]; 81 bool bi=(a>=phi[L]); 82 for(int i=L;i>=1;i--){ 83 ret=Pow(c,ret+((bi==true)?phi[i]:0),phi[i-1],bi); 84 } 85 return ret; 86 } 87 void change(int a,int b,int k,int L,int R){ 88 if(cnt[k]>=tot-1){ 89 return ; 90 } 91 if(b<=L||R<=a){ 92 return ; 93 } 94 if(L+1==R){ 95 cnt[k]++; 96 dat[k]=solve(::a[L],cnt[k]); 97 return ; 98 } 99 change(a,b,k<<1,L,(L+R)>>1); 100 change(a,b,k<<1|1,(L+R)>>1,R); 101 dat[k]=(dat[k<<1]+dat[k<<1|1])%MOD; 102 cnt[k]=min(cnt[k<<1],cnt[k<<1|1]); 103 } 104 int query(int a,int b,int k,int L,int R){ 105 if(b<=L||R<=a){ 106 return 0; 107 } 108 else if(a<=L&&R<=b){ 109 return dat[k]; 110 } 111 else{ 112 int lc=query(a,b,k<<1,L,(L+R)>>1); 113 int rc=query(a,b,k<<1|1,(L+R)>>1,R); 114 return (lc+rc)%MOD; 115 } 116 } 117 void build(int k,int L,int R){ 118 if(L+1==R){ 119 dat[k]=a[L]; 120 return ; 121 } 122 build(k<<1,L,(L+R)>>1); 123 build(k<<1|1,(L+R)>>1,R); 124 dat[k]=(dat[k<<1]+dat[k<<1|1])%MOD; 125 } 126 int main() 127 { 128 //freopen("data.in","r",stdin); 129 //freopen("my.out","w",stdout); 130 int T; 131 scanf("%d%d%d%d",&n,&T,&MOD,&c); 132 work(MOD); 133 phi[tot++]=1; 134 for(int i=1;i<=n;i++){ 135 scanf("%d",&a[i]); 136 } 137 build(1,1,n+1); 138 // if(DEBUG){ 139 // for(int i=1;i<=n;i++){ 140 // printf("%d ",query(i,i+1,1,1,n+1)); 141 // } 142 // printf(" "); 143 // } 144 for(int i=1;i<=T;i++){ 145 int p,L,R; 146 scanf("%d%d%d",&p,&L,&R); 147 if(!p){ 148 change(L,R+1,1,1,n+1); 149 } 150 else{ 151 printf("%d ",query(L,R+1,1,1,n+1)); 152 } 153 // if(DEBUG){ 154 // for(int i=1;i<=n;i++){ 155 // printf("%d ",query(i,i+1,1,1,n+1)); 156 // } 157 // printf(" "); 158 // } 159 } 160 return 0; 161 }