题意:
给定
n
n
n个数和
q
q
q个询问,询问有两种:
1.
1.
1.给定
i
i
i和
v
a
l
val
val,将
a
[
i
]
a[i]
a[i]的值更新为
v
a
l
val
val
2.
2.
2.给定
i
i
i,求
∑
j
=
1
n
a
[
j
]
(
g
c
d
(
i
,
j
)
=
=
1
)
\sum_{j=1}^n a[j](gcd(i,j) == 1)
∑j=1na[j](gcd(i,j)==1)
思路:
考虑询问操作的实现:
由艾弗森约定,得:
A
n
s
=
∑
j
=
1
n
a
[
j
]
(
g
c
d
(
i
,
j
)
=
=
1
)
=
∑
j
=
1
n
a
[
j
]
∑
d
∣
g
c
d
(
i
,
j
)
μ
[
d
]
Ans = \sum_{j=1}^n a[j](gcd(i,j) == 1) = \sum_{j=1}^n a[j] \sum_{d|gcd(i,j)} \mu[d]
Ans=j=1∑na[j](gcd(i,j)==1)=j=1∑na[j]d∣gcd(i,j)∑μ[d]
转换枚举变量为
d
d
d,则
A
n
s
=
∑
d
=
1
n
μ
[
d
]
∗
∑
j
=
1
⌊
n
d
⌋
a
[
j
∗
d
]
Ans = \sum_{d=1}^n \mu[d] * \sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}a[j*d]
Ans=d=1∑nμ[d]∗j=1∑⌊dn⌋a[j∗d] (
d
d
d为
i
i
i的约数)
令
s
u
m
[
x
]
=
∑
i
=
1
⌊
n
x
⌋
a
[
i
∗
x
]
sum[x] = \sum_{i=1}^{\lfloor\frac{n}{x}\rfloor} a[i*x]
sum[x]=i=1∑⌊xn⌋a[i∗x]
则:
A
n
s
=
∑
d
=
1
n
μ
[
d
]
∗
s
u
m
[
d
]
Ans = \sum_{d=1}^n \mu[d] *sum[d]
Ans=d=1∑nμ[d]∗sum[d]
(
d
d
d为
i
i
i的约数)
故询问的复杂度为: O ( n ) O(\sqrt n) O(n)
而对于更新操作,只需要更新 s u m sum sum中下标为 i i i的约数的元素值,复杂度为: O ( n ) O(\sqrt n) O(n)
另外需要预处理 s u m sum sum和 μ \mu μ,复杂度为 O ( n ) O(n) O(n)
总复杂度: O ( n + q n ) O(n + q\sqrt n) O(n+qn)
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
#define lson rt<<1
#define rson rt<<1|1
const int A = 1e5 + 10;
int a[A],sum[A],pri[A],mu[A],tot,n,q;
bool vis[A];
void init(){
for(int i=0 ;i<=n ;i++) sum[i] = 0;
for(int i=1 ;i<=n ;i++){
for(int j=i ;j<=n ;j+=i){
sum[i] += a[j];
}
}
tot = 0,mu[1] = 1;
for(int i=2 ;i<A ;i++){
if(!vis[i]) pri[++tot] = i,mu[i] = -1;
for(int j=1 ;j<=tot && i*pri[j] < A ;j++){
vis[i*pri[j]] = 1;
if(i%pri[j] == 0){
mu[i*pri[j]] = 0;
break;
}
mu[i*pri[j]] = -mu[i];
}
}
}
void update(int x,int val){
for(int i=1 ;i*i<=x ;i++){
if(x%i == 0){
sum[i] = sum[i] - a[x] + val;
if(i*i != x){
sum[x/i] = sum[x/i] - a[x] + val;
}
}
}
a[x] = val;
}
ll query(int x){
ll ans = 0;
for(int i=1 ;i*i<=x ;i++){
if(x%i == 0){
ans += mu[i]*sum[i];
if(i*i != x){
ans += mu[x/i]*sum[x/i];
}
}
}
return ans;
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1 ;i<=n ;i++) scanf("%d",&a[i]);
init();
while(q--){
int type;scanf("%d",&type);
if(type == 1){
int id,x;
scanf("%d%d",&id,&x);
update(id,x);
}
else{
int id;
scanf("%d",&id);
printf("%lld\n",query(id));
}
}
return 0;
}