/*
51nod 1678
这天,lyk又和gcd杠上了。
它拥有一个n个数的数列,它想实现两种操作。
1:将 ai 改为b。
2:给定一个数i,求所有 gcd(i,j)=1 时的 aj 的总和。
直接暴力做超时
而且直接求互质的数不好求
所以我们考虑求不互质的数
然后用容斥原理
用容斥原理前我们先把每个数的倍数
所对应的那个数的和求出来存入tmp数组
如tmp[i]就表示i的倍数所对应的数求和
所以我们在更改的时候也要把这个更改
接下来就是容斥原理
*/
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <math.h>
#include <string.h>
#define mod 1000000007
#define MAX 100005
#define ll long long
#define PI acos(-1)
using namespace std;
int p[100005];
int prime[100005];
int k;
inline void isprime()//筛选出素数
{
k=0;
memset(prime,0,sizeof(prime));
for(int i=2; i*i<100002; i++)
{
if(!prime[i])
{
p[k++]=i;
for(int j=i*i; j<100005; j=j+i)
prime[j]=1;
}
}
}
int a[100005];//存一开始给的n个数
int tmp[100005];//tmp[i],表示为所有是 i 的倍数的数字的和
int b[1005];//存质因数
int main()
{
isprime();
int n,Q;
while(scanf("%d%d",&n,&Q)!=EOF)
{
int sum=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
memset(tmp,0,sizeof(tmp));
for(int i=2;i<=n;i++)//将i的倍数相加
for(int j=1;i*j<=n;j++)
tmp[i]+=a[i*j];
while(Q--)
{
int A;
scanf("%d",&A);
if(A==1)
{
int s,w;
scanf("%d%d",&s,&w);
sum-=a[s];
tmp[s]-=a[s];
tmp[s]+=w;
for(int i=2;i*i<=s;i++)
{
if(i*i==s)//当s为平方数有一种特殊情况
{
tmp[i]-=a[s];
tmp[i]+=w;
continue;
}
if(s%i==0)
{
tmp[i]-=a[s];
tmp[i]+=w;
tmp[s/i]-=a[s];
tmp[s/i]+=w;
}
}
a[s]=w;
sum+=w;
}
else
{
int s;
scanf("%d",&s);
int cut=0,num=s;
for(int i=0;p[i]*p[i]<=num&&i<k;i++)//质因数分解
{
if(num%p[i]==0)
b[cut++]=p[i];
while(num%p[i]==0)
num/=p[i];
}
if(num>1)
b[cut++]=num;
int ans=0;
for(int i=1;i<(1<<cut);i++)//用状态压缩自由组合素因子
{
int res=1,flag=0;
for(int j=0;j<cut;j++)
{
if(((i>>j)&1)==1)
{
res*=b[j];
flag++;
}
}
if(flag%2)//容斥
ans=ans+tmp[res];
else
ans=ans-tmp[res];
}
cout<<sum-ans<<endl;
}
}
}
return 0;
}
51nod 1678
这天,lyk又和gcd杠上了。
它拥有一个n个数的数列,它想实现两种操作。
1:将 ai 改为b。
2:给定一个数i,求所有 gcd(i,j)=1 时的 aj 的总和。
直接暴力做超时
而且直接求互质的数不好求
所以我们考虑求不互质的数
然后用容斥原理
用容斥原理前我们先把每个数的倍数
所对应的那个数的和求出来存入tmp数组
如tmp[i]就表示i的倍数所对应的数求和
所以我们在更改的时候也要把这个更改
接下来就是容斥原理
*/
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <math.h>
#include <string.h>
#define mod 1000000007
#define MAX 100005
#define ll long long
#define PI acos(-1)
using namespace std;
int p[100005];
int prime[100005];
int k;
inline void isprime()//筛选出素数
{
k=0;
memset(prime,0,sizeof(prime));
for(int i=2; i*i<100002; i++)
{
if(!prime[i])
{
p[k++]=i;
for(int j=i*i; j<100005; j=j+i)
prime[j]=1;
}
}
}
int a[100005];//存一开始给的n个数
int tmp[100005];//tmp[i],表示为所有是 i 的倍数的数字的和
int b[1005];//存质因数
int main()
{
isprime();
int n,Q;
while(scanf("%d%d",&n,&Q)!=EOF)
{
int sum=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
memset(tmp,0,sizeof(tmp));
for(int i=2;i<=n;i++)//将i的倍数相加
for(int j=1;i*j<=n;j++)
tmp[i]+=a[i*j];
while(Q--)
{
int A;
scanf("%d",&A);
if(A==1)
{
int s,w;
scanf("%d%d",&s,&w);
sum-=a[s];
tmp[s]-=a[s];
tmp[s]+=w;
for(int i=2;i*i<=s;i++)
{
if(i*i==s)//当s为平方数有一种特殊情况
{
tmp[i]-=a[s];
tmp[i]+=w;
continue;
}
if(s%i==0)
{
tmp[i]-=a[s];
tmp[i]+=w;
tmp[s/i]-=a[s];
tmp[s/i]+=w;
}
}
a[s]=w;
sum+=w;
}
else
{
int s;
scanf("%d",&s);
int cut=0,num=s;
for(int i=0;p[i]*p[i]<=num&&i<k;i++)//质因数分解
{
if(num%p[i]==0)
b[cut++]=p[i];
while(num%p[i]==0)
num/=p[i];
}
if(num>1)
b[cut++]=num;
int ans=0;
for(int i=1;i<(1<<cut);i++)//用状态压缩自由组合素因子
{
int res=1,flag=0;
for(int j=0;j<cut;j++)
{
if(((i>>j)&1)==1)
{
res*=b[j];
flag++;
}
}
if(flag%2)//容斥
ans=ans+tmp[res];
else
ans=ans-tmp[res];
}
cout<<sum-ans<<endl;
}
}
}
return 0;
}