题目链接
题意:
给定 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
#include
#include
#include
#include
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;
}