题意:给你一个数1~n的序列,m次操作,每次操作可以单点修改,即把a【i】的值改成c; 或一次区间查询,玩第x个数到第y个数之间与p互质的数的和
m<1000; 其他的数<=400000
解析:初看以为是线段树,但大神说是容斥原理,一个p查询进行一次容斥,居然不超时。。。。。。
#include<iostream>
#include<cstdio>
#include<string.h>
#include<math.h>
#include<vector>
using namespace std;
#define N 400001
typedef __int64 LL;
LL a[N],prime[N];
int gcd(int x,int y)
{
return y==0?x:gcd(y,x%y);
}
void inint()
{
memset(a,0,sizeof(a));
int i,j,k,c=1;
for(i=2; i<N; i++)
{
if(!a[i]) prime[c++]=i;
for(j=1; j<c&&(k=i*prime[j])<N; j++)
{
a[k]=1;
if(i%prime[j]==0) break;
}
}
}
struct node
{
int x,c;
};
vector<node> swa;
vector<int> zhi;
LL res;
int n,m,p,x,y;
LL cal(int x, int p)
{
LL ret = (LL)x*(x+1)/2;
for (int s=1; s<(1<<zhi.size()); s++)
{
int cnt = 0;
int v = 1;
for (int i=0; i<zhi.size(); i++)
if (s & (1<<i))
{
cnt++;
v *= zhi[i];
}
LL k = x / v;
k = k*(k+1)*v/2;
if (cnt % 2 == 1) ret -= k;
else ret += k;
}
return ret;
}
int main()
{
int i,j,t,c,z;
inint();
scanf("%d",&t);
node v;
while(t--)
{
scanf("%d%d",&n,&m);
swa.clear();
while(m--)
{
scanf("%d",&z);
if(z==1)
{
zhi.clear();
scanf("%d%d%d",&x,&y,&p);
int k=p;
for(i=1; prime[i]<=k; i++)
{
if(k%prime[i]==0)
{
zhi.push_back(prime[i]);
}
while (k % prime[i] == 0) k /= prime[i]; //没有这语句的话就超时
if(k==1) break;
}
res=cal(y,p);
res-=cal(x-1,p);
for(i=0; i<swa.size(); i++)
{
if (swa[i].x >= x&&swa[i].x<=y)
{
if (gcd(swa[i].x, p) == 1) res -= swa[i].x;
if (gcd(swa[i].c, p) == 1) res += swa[i].c;
}
}
printf("%I64d\n",res);
}
else
{
scanf("%d%d",&x,&c);
int ff=1;
for(i=0; i<swa.size(); i++)
{
if(swa[i].x==x)
{
swa[i].c=c;
ff=0;
}
}
v.x=x;
v.c=c;
if(ff)
swa.push_back(v);
}
}
}
return 0;
}
/*
88
130 100
1 1 130 26
1 1 130 39
1 39 130 130
1 41 141 1
*/