题意: 有一个元素为 1~n (n<=4e5)的数列{An},有2种操作,m次(1000次):
1、求某段区间 [a,b] 中与 p 互质的数的和。
2、将数列中某个位置元素的值改变。
这题因为m很小,所以可以暴力处理m,那么我们先考虑元数组为1-n,问题就简单多了
先求出【1,x】内 与p互质的数有多少个,根据欧拉定理就可以求啦,也就是求出p的质数,然后容斥一下得到与p互质的数的个数。
num1=get(1,x-1),num2=get(1,y), 如果没有修改操作的话,ans应该就是num2-num1,但是因为m操作太少了,我们直接暴力记录一下操作,把修改过的元素下标存到set,每次遍历处于【x,y】之间的修改过的下标,如果原来这个数与p互质,答案减1。如果修改后的数与p互质,答案加1.
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
const long long maxn=400010;
set<long long> s;
set<long long>::iterator it;
long long px[10];
long long n,m;
long long a[maxn],prime[maxn],tot=0;
bool flag[maxn];
long long gcd(long long a,long long b)
{
if (!b) return a;
return gcd(b,a % b);
}
long long get(long long x,long long p)
{
long long k=0,pp=p;
for (long long i=1; prime[i]*prime[i]<=pp; i++)
{
if (flag[pp]) break;
if (pp % prime[i]==0)
{
px[k++]=prime[i];
while (pp % prime[i]==0)
pp/=prime[i];
}
}
if (pp!=1)
px[k++]=pp;
long long tmp=0;
for (long long state=1; state<(1<<k); state++)
{
long long num=0,q=1;
for (long long j=0; j<k; j++)
if (state & (1<<j))
{
num++;
q*=px[j];
}
long long num2=x/q;
if (num % 2)
tmp=tmp+num2*(q+q*num2)/2;
else
tmp=tmp-num2*(q+q*num2)/2;
}
return (1+x)*x/2-tmp;
}
int main()
{
//freopen("input.txt","r",stdin);
long long tt;scanf("%lld",&tt);
memset(flag,1,sizeof(flag));
for (long long i=2; i<=400000; i++)
{
if (flag[i])
{
prime[++tot]=i;
for (long long j=i*i; j<=400000; j+=i)
flag[j]=0;
}
}
while (tt--)
{
scanf("%lld%lld",&n,&m);
s.clear();
memset(a,0,sizeof(a));
for (long long i=1; i<=m; i++)
{
long long op,x,y,p,c;
scanf("%lld",&op);
if (op==1)
{
scanf("%lld%lld%lld",&x,&y,&p);
long long num1=get(x-1,p);
long long num2=get(y,p);
long long tmp=num2-num1;
it=s.lower_bound(x);
for (; it!=s.end(); it++)
if (*it>=x && *it<=y)
{
if (gcd(p,*it)==1)
tmp-=(*it);
if (gcd(p,a[*it])==1)
tmp+=a[*it];
}
else
break;
printf("%lld\n",tmp);
}
else
{
scanf("%lld%lld",&x,&c);
s.insert(x);
a[x]=c;
}
}
}
return 0;
}