[Shoi2017]相逢是问候(拓展欧拉公式)
这题和依旧是拓展欧拉定理
注意到phi的只要log次就能修改成1,因为
gcd(n,x)==gcd(n, n-x)
所以n>=3时,phi(n)为偶数,而偶数的phi显然至少除2
对了这里判断x和phi(p)的大小时,我是记录了一个flag,表示是否取过mod,去过则大于,返回x%phi(p)+phi(p)
每个点只会涉及到log(n)次的修改,网上搜了下大家都是用线段树
比较懒qwq 感觉线段树比较难敲,想了想了发现做过类似的题,可以用树状数组加并查集水过去。
每个点维护一下从它到最后 最前能修改的点是谁 然后每次修改,树状数组维护
最近debug能力大幅下降感觉,这都改了好久qwq
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 51000;
int n, m, p, c;
struct Tbit{
int b[maxn], m;
void clear(int size){ m = size; memset(b, 0, sizeof(b)); }
void modify(int x, int ad){
if (ad < 0) ad += p;
for (int i = x; i <= m; i += i&-i)
b[i] += ad, b[i] %= p;
}
int sum(int x){
int ans = 0;
for (int i = x; i; i -= i&-i)
ans += b[i], ans %= p;
return ans;
}
int sum(int x, int y){ return s#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 151000;
int n, m, p, c;
struct Tbit{
int b[maxn], m;
void clear(int size){ m = size; memset(b, 0, sizeof(b)); }
void modify(int x, int ad){
if (ad < 0) ad += p;
for (int i = x; i <= m; i += i&-i)
b[i] += ad, b[i] %= p;
}
int sum(int x){
int ans = 0;
for (int i = x; i; i -= i&-i)
ans += b[i], ans %= p;
return ans;
}
int sum(int x, int y){ return ((sum(y) - sum(x - 1))%p + p) % p; }
}bit;
struct Tunf{
int fa[maxn];
void clear(int size){
for (int i = 1; i <= size; i ++)
fa[i] = i;
}
int find(int x){
if (x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
void cc(int x, int y){ fa[find(x)] = find(y); }
}unf;
int tmt[maxn], a[maxn], b[maxn];
void init(){
scanf("%d%d%d%d", &n, &m, &p, &c);
bit.clear(n);
for (int i = 1; i <= n; i ++){
scanf("%d", &a[i]);
bit.modify(i, b[i] = a[i]);
}
}
map<int, int> PHI;
int phi(int x){
if (x == 1) return 1;
if (PHI[x]) return PHI[x];
int ans = x, y = x;
for (int i = 2; i * i <= x; i ++) if (x % i == 0){
ans = 1LL * ans * (i - 1) / i;
while (x % i == 0) x /= i;
}
if (x != 1) ans = 1LL * ans * (x - 1) / x;
return PHI[y] = ans;
}
int pw(int x, int i, int p, bool &flag){
// cout <<"PW" << ' ' <<x << ' '<<i<<endl;
int k = x; ll ans = 1;
while (i){
if (i&1){
ans = ans * k;
if (ans >= p) flag = 1, ans %= p;
}
i >>= 1;
if (i) flag |= (1LL * k * k >= p);
k = 1LL * k * k % p;
}
return ans;
}
int func(int x, int dep, int p){
if (c == 1) return 1;
if (dep == 0){
// cout <<x <<' ' <<p <<' ' <<x % p + (x >= p?p:0) <<endl;
return x % p + (x >= p?p:0);
}
bool flag = 0;
int asd = 0;
int tmp = pw(c, asd = func(x, dep - 1, phi(p)), p, flag);
// cout <<x <<' ' <<asd <<' ' <<dep <<' ' <<tmp <<' ' <<flag <<' ' <<p <<' '<<phi(p) <<endl;
return tmp + (flag?p:0);
}
void work(){
unf.clear(n);
int mxlen = 2, tmp = p;
while (tmp > 1) tmp = phi(tmp), mxlen ++;
// cout <<mxlen <<endl;
for (int i = 1; i <= m; i ++){
int op, l, r; scanf("%d%d%d", &op, &l, &r);
if (op == 0){
int nw = unf.find(l);
while (nw <= r && nw){
// cout <<nw <<endl;
int tmp = func(a[nw], ++ tmt[nw], p);
tmp %= p;
// cout <<tmp <<' ' <<b[nw] <<endl;
bit.modify(nw, tmp - b[nw]);
b[nw] = tmp;
if (tmt[nw] == mxlen + 1) unf.cc(nw, nw + 1);
nw = unf.find(nw + 1);
}
}else printf("%d\n", bit.sum(l, r));
}
}
int main(){
init();
work();
return 0;
}