题目大意:
我们定义一个非负整数是“好数”,当且仅当它符合以下条件之一:
1.这个数是
0
0
0或
1
1
1。
2.所有小于这个数且与它互质的正整数可以排成一个等差数列。
给出
N
N
N个非负整数,然后进行如下三个操作:
1.询问区间
[
L
,
R
]
[L,R]
[L,R]有多少个好数
2.将区间
[
L
,
R
]
[L,R]
[L,R]内所有数对
S
S
S取余
S
≤
1000000
S≤1000000
S≤1000000
3.将第
C
C
C个数更改为
X
X
X
操作数为
M
M
M
分析:
首先我们可以发现,
对于一个数而言,当且仅当是
①
0
0
0,②
1
1
1,③
6
,
6,
6,④
2
2
2的幂次,才是好数
这个可以打表或者手丸一下就知道了
现在有一个结论,
一个数
x
x
x,如果
m
o
d
mod
mod上一个数
y
y
y,当
y
≤
x
y≤x
y≤x的时候,
显然有
x
x
x
m
o
d
mod
mod
y
y
y
≤
≤
≤
x
/
2
x/2
x/2
证明的话,
前提为
y
≤
x
y≤x
y≤x
当
y
≤
x
/
2
y≤x/2
y≤x/2,
则显然
x
x
x
m
o
d
mod
mod
y
y
y
≤
≤
≤
y
y
y
=
>
=>
=>
x
x
x
m
o
d
mod
mod
y
y
y
≤
≤
≤
x
/
2
x/2
x/2
当
y
>
x
/
2
y>x/2
y>x/2,
则也显然
x
x
x
m
o
d
mod
mod
y
y
y
=
>
=>
=>
x
−
y
x-y
x−y,根据
x
−
(
x
/
2
)
≤
x
/
2
x-(x/2)≤x/2
x−(x/2)≤x/2可以得到
x
−
y
≤
x
/
2
x-y≤x/2
x−y≤x/2,
那么就有
x
x
x
m
o
d
mod
mod
y
y
y
≤
≤
≤
x
/
2
x/2
x/2
所以当
y
≤
x
y≤x
y≤x的时候,
显然都有
x
x
x
m
o
d
mod
mod
y
y
y
≤
≤
≤
x
/
2
x/2
x/2
那么我们可以发现,对于任意一个数
x
x
x对它进行的有效操作至多就是
l
o
g
2
x
log_2 x
log2x次了
因为每个数都不超过
1
e
6
1e6
1e6,
那么我们就可以线段树大力做,
每次维护一下区间最大值,如果模数
S
>
S>
S>区间最大值,则这个区间的任意一个数
m
o
d
mod
mod
S
S
S都是无效操作
然后可以了
修改呀,区间求总数和,那些就是线段树的经典操作了吧
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <algorithm>
#define lson(x) x * 2
#define rson(x) x * 2 + 1
#define M 1000005
#define N 100005
using namespace std;
struct Node { int MaxNum, total; }tree[5*N];
int prime[N], A[N], n, m, cnt, Sum_total;
bool good[M];
void read(int &x)
{
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = - 1; s = getchar(); }
while (s >= '0' && s <= '9') { x = x * 10 + (s - '0'); s = getchar(); }
x = x * f;
}
void Pre_Work()
{
for (int i = 0; i <= 1000000; i++) good[i] = 1;
for (int i = 2; i <= 1000000; i++)
{
if (good[i]) prime[++cnt] = i, good[i] = 1;
for (int j = 1; j <= cnt; j++)
{
if (i * prime[j] > 1000000) break;
good[i * prime[j]] = 0;
if (i % prime[j] == 0) break;
}
}
int x = 1;
for (; x <= 1000000; x <<= 1) good[x] = 1;
good[6] = 1;
}
void Update(int G)
{
tree[G].MaxNum = max(tree[lson(G)].MaxNum, tree[rson(G)].MaxNum);
tree[G].total = tree[lson(G)].total + tree[rson(G)].total;
}
void Build(int G, int l, int r)
{
if (l == r)
{
if (good[A[l]]) tree[G].total = 1; else tree[G].total = 0;
tree[G].MaxNum = A[l];
return;
}
int mid = (l + r) >> 1;
Build(lson(G), l, mid);
Build(rson(G), mid + 1, r);
Update(G);
}
void Get_Sum(int G, int l, int r, int x, int y)
{
if (l == x && r == y)
{
Sum_total += tree[G].total;
return;
}
int mid = (l + r) >> 1;
if (y <= mid) Get_Sum(lson(G), l, mid, x, y);
else if (x > mid) Get_Sum(rson(G), mid + 1, r, x, y);
else
{
Get_Sum(lson(G), l, mid, x, mid);
Get_Sum(rson(G), mid + 1, r, mid + 1, y);
}
}
void Change_wxy(int G, int l, int r, int x, int y, int modn)
{
if (l == r)
{
A[l] = A[l] % modn;
tree[G].MaxNum = A[l];
if (good[A[l]]) tree[G].total = 1; else tree[G].total = 0;
return;
}
int mid = (l + r) >> 1;
if (l == x && r == y)
{
if (tree[G].MaxNum < modn) return;
Change_wxy(lson(G), l, mid, x, mid, modn);
Change_wxy(rson(G), mid + 1, r, mid + 1, y, modn);
Update(G);
return;
}
if (y <= mid) Change_wxy(lson(G), l, mid, x, y, modn);
else if (x > mid) Change_wxy(rson(G), mid + 1, r, x, y, modn);
else
{
Change_wxy(lson(G), l, mid, x, mid, modn);
Change_wxy(rson(G), mid + 1, r, mid + 1, y, modn);
}
Update(G);
}
void Change_yzh(int G, int l, int r, int id, int num)
{
if (l == r)
{
A[l] = num;
tree[G].MaxNum = A[l];
if (good[A[l]]) tree[G].total = 1; else tree[G].total = 0;
return;
}
int mid = (l + r) >> 1;
if (id <= mid) Change_yzh(lson(G), l, mid, id, num);
else if (id > mid) Change_yzh(rson(G), mid + 1, r, id, num);
Update(G);
}
int main()
{
Pre_Work();
read(n); read(m);
for (int i = 1; i <= n; i++) read(A[i]);
Build(1, 1, n);
int opt, l, r, x, modn;
while (m--)
{
read(opt);
if (opt == 1)
{
read(l); read(r); Sum_total = 0;
Get_Sum(1, 1, n, l, r);
printf("%d\n", Sum_total);
}
if (opt == 2)
{
read(l); read(r); read(modn);
Change_wxy(1, 1, n, l, r, modn);
}
if (opt == 3)
{
read(l); read(x);
Change_yzh(1, 1, n, l, x);
}
}
return 0;
}