Description:
给定一个数列,有两种操作,询问一段区间
[l,r]
[
l
,
r
]
内的和或者对于
[l,r]
[
l
,
r
]
的所有
x
x
平方。
Solution:
由于很小,所以平方会有循环节,所有循环节的
lcm
l
c
m
不超过
60
60
。那么预处理循环节即可。
那么我们每次修改的时候看当前区间是否处于循环中,否则暴力递归修改。
注意下传标记时可能当前区间并未进入循环,导致循环节长度为
0
0
从而。
#include <bits/stdc++.h>
using namespace std;
const int N = 4e5 + 5;
int n, m, P;
int len[N], c[N][65], pos[N], tag[N], sum[N], in[N], inc[N], nxt[N], vis[N], gg[N];
namespace IO
{
const int Maxlen = N * 50;
char buf[Maxlen], *C = buf;
int Len;
inline void read_in()
{
Len = fread(C, 1, Maxlen, stdin);
buf[Len] = '\0';
}
inline void fread(int &x)
{
x = 0;
int f = 1;
while (*C < '0' || '9' < *C) { if(*C == '-') f = -1; ++C; }
while ('0' <= *C && *C <= '9') x = (x << 1) + (x << 3) + *C - '0', ++C;
x *= f;
}
inline void fread(long long &x)
{
x = 0;
long long f = 1;
while (*C < '0' || '9' < *C) { if(*C == '-') f = -1; ++C; }
while ('0' <= *C && *C <= '9') x = (x << 1) + (x << 3) + *C - '0', ++C;
x *= f;
}
inline void read(int &x)
{
x = 0;
int f = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + c - '0'; c = getchar(); }
x *= f;
}
inline void read(long long &x)
{
x = 0;
long long f = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { x = (x << 1ll) + (x << 3ll) + c - '0'; c = getchar(); }
x *= f;
}
} using namespace IO;
inline int lcm(int a, int b) {
return a / __gcd(a, b) * b;
}
inline void paint(int x, int d) {
tag[x] += d;
pos[x] += d;
if(pos[x] >= len[x]) {
pos[x] %= len[x];
}
sum[x] = c[x][pos[x]];
}
inline void pushdown(int x) {
if(tag[x]) {
paint(x << 1, tag[x]);
paint(x << 1 | 1, tag[x]);
tag[x] = 0;
}
}
void ini(int x, int v) {
sum[x] = v;
in[x] = inc[v];
if(in[x]) {
pos[x] = 0;
len[x] = 1;
c[x][0] = v;
for(int i = nxt[v]; i != v; i = nxt[i]) {
c[x][len[x]++] = i;
}
}
}
void upd(int x) {
sum[x] = sum[x << 1] + sum[x << 1 | 1];
in[x] = in[x << 1] & in[x << 1 | 1];
if(in[x]) {
len[x] = lcm(len[x << 1], len[x << 1 | 1]);
pos[x] = 0;
for(int i = 0, p1 = pos[x << 1], p2 = pos[x << 1 | 1]; i < len[x]; ++i) {
c[x][i] = c[x << 1][p1++] + c[x << 1 | 1][p2++];
if(p1 == len[x << 1]) {
p1 = 0;
}
if(p2 == len[x << 1 | 1]) {
p2 = 0;
}
}
pos[x] = 0;
}
}
void build(int l, int r, int x) {
if(l == r) {
ini(x, gg[l]);
return;
}
int mid = (l + r) >> 1;
build(l, mid, x << 1);
build(mid + 1, r, x << 1 | 1);
upd(x);
}
void update(int l, int r, int x, int a, int b) {
if(l > b || r < a) {
return;
}
if(l >= a && r <= b && in[x]) {
paint(x, 1);
return;
}
if(l == r) {
ini(x, nxt[gg[l]]);
gg[l] = nxt[gg[l]];
return;
}
pushdown(x);
int mid = (l + r) >> 1;
update(l, mid, x << 1, a, b);
update(mid + 1, r, x << 1 | 1, a, b);
upd(x);
}
int query(int l, int r, int x, int a, int b) {
if(l > b || r < a) {
return 0;
}
if(l >= a && r <= b) {
return sum[x];
}
pushdown(x);
int mid = (l + r) >> 1;
return query(l, mid, x << 1, a, b) + query(mid + 1, r, x << 1 | 1, a, b);
}
int main() {
read_in();
fread(n);
fread(m);
fread(P);
for(int i = 1; i <= n; ++i) {
fread(gg[i]);
}
for(int i = 0; i < P; ++i) {
nxt[i] = (i * i) % P;
inc[i] = 1;
}
for(int i = 0; i < P; ++i) {
if(!vis[i]) {
int t;
for(t = i; !vis[t]; t = nxt[t]) {
vis[t] = 1;
}
for(int p = i; p != t; p = nxt[p]) {
inc[p] = 0;
}
}
}
build(1, n, 1);
while(m--) {
int opt, l, r;
fread(opt);
fread(l);
fread(r);
if(!opt) {
update(1, n, 1, l, r);
} else {
printf("%d\n", query(1, n, 1, l, r));
}
}
return 0;
}