这天,lyk又和gcd杠上了。
它拥有一个n个数的数列,它想实现两种操作。
1:将 aiai 改为b。
2:给定一个数i,求所有 gcd(i,j)=1gcd(i,j)=1 时的 ajaj 的总和。
收起
第一行两个数n,Q(1<=n,Q<=100000)。
接下来一行n个数表示ai(1<=ai<=10^4)。
接下来Q行,每行先读入一个数A(1<=A<=2)。
若A=1,表示第一种操作,紧接着两个数i和b。(1<=i<=n,1<=b<=10^4)。
若B=2,表示第二种操作,紧接着一个数i。(1<=i<=n)。
对于每个询问输出一行表示答案。
5 3
1 2 3 4 5
2 4
1 3 1
2 4
9
7
设,那么,sum(d)可以直接打表得到,复杂度为nlogn。
(1)对于修改操作我们可以发现只有当d|i时a[i]才会对sum[d]产生影响,因此我们在时间内枚举i的因子,修改对应的sum[d]。
代码:
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int mu[maxn],mark[maxn],sum[maxn],prime[maxn],a[maxn];
void get(){
mu[1] = 1;
for(int i = 2;i < maxn;++i){
if(!mark[i]) prime[++prime[0]] = i,mu[i] = -1;
for(int j = 1;j <= prime[0] && i * prime[j] < maxn;++j){
mark[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
}
}
void update(int i,int v){
for(int d = 1;d * d <= i;++d)
if(i % d == 0){
sum[d] += v - a[i];
if(d * d != i) sum[i / d] += v - a[i];
}
a[i] = v;
}
int query(int i){
int ans = 0;
for(int d = 1;d * d <= i;++d)
if(i % d == 0){
ans += mu[d] * sum[d];
if(d * d != i) ans += mu[i / d] * sum[i / d];
}
return ans;
}
int main(){
get();
int n,q,o,b,c;
scanf("%d%d",&n,&q);
for(int i = 1;i <= n;++i) scanf("%d",&a[i]);
for(int i = 1;i <= n;++i){
sum[i] = 0;
for(int j = i;j <= n;j += i)
sum[i] += a[j];
}
for(int i = 1;i <= q;++i){
scanf("%d",&o);
if(o == 1){
scanf("%d%d",&b,&c);
update(b,c);
}else{
scanf("%d",&b);
printf("%d\n",query(b));
}
}
return 0;
}