hdu4407
题解:如果我们暴力去针对每一次查询就会超时,又发现题目中的修改最多不过1000次,所以我们在查询一段区间的时候可以先求出x到y这一段连续区间的等差数列的和,然后减去该区间和p互素的数的和(该部分值我们可以用先把p的素因子找出来然后在x到y区间容斥一下)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
const LL maxn=4e5+10;
LL prime[maxn],cnt;
LL a[maxn];
LL n,m;
LL es[maxn],mp[maxn],tot;
LL b[maxn];
LL ans;
LL x,y,p,c;
void dfs(LL pos,LL flag,LL t,LL f)
{
if(t>y){
return;
}
if(pos>cnt){
if(f!=0){
LL N=y/t;
LL pre=(N+1)*(N*t)/2;
LL N1=(x-1)/t;
LL pre1=(N1+1)*(N1*t)/2;
ans+=(flag*(pre-pre1));
}
return;
}
dfs(pos+1,flag,t,f);
LL gcd=__gcd(b[pos],t);
LL lcm=(b[pos]*t)/gcd;
dfs(pos+1,-flag,lcm,f+1);
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
tot=0;
scanf("%lld%lld",&n,&m);
for(LL i=0;i<=n;i++){
es[i]=0;mp[i]=0;
}
int op;
for(LL i=1;i<=m;i++){
scanf("%d",&op);
if(op==1){
scanf("%lld%lld%lld",&x,&y,&p);
cnt=0;
LL pre=p;
for(LL j=2;j*j<=p;j++){
if(pre%j==0){
while(pre%j==0){
pre/=j;
}
b[++cnt]=j;
}
}
if(pre>1){
b[++cnt]=pre;
}
LL res=(x+y)*(y-x+1)/2;
ans=0;
dfs(1,-1,1,0);
res-=ans;
for(LL j=1;j<=tot;j++){
LL s=es[j];
if(s>=x&&s<=y){
LL l=__gcd(s,p),r=__gcd(mp[s],p);
if(l==1&&r==1){
res-=s;
res+=mp[s];
}
if(l==1&&r!=1){
res-=s;
}
if(l!=1&&r==1){
res+=mp[s];
}
if(l!=1&&r!=1){
res+=0;
}
}
}
printf("%lld\n",res);
}
else{
scanf("%lld%lld",&x,&c);
if(mp[x]>0){
mp[x]=c;
}
else{
es[++tot]=x;
mp[x]=c;
}
}
}
}
return 0;
}