http://acm.hdu.edu.cn/showproblem.php?pid=4407
把修改和询问分成两部分解决
询问求区间内与p不互素的和,和求个数一样,用容斥原理解决,只不过做容斥的时候把每一段的个数改成每一段的和,这个求和的方式我一下写搓了,导致这道题坑了很久
修改用map记录,每次扫一遍即可,原数和c互素就减掉,修改完的数和c互素就加上去,logn*m^2的复杂度
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <map> #include <cmath> using namespace std; typedef __int64 ll; ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); } ll sum(ll l,ll r,ll k){ ll num=r/k-(l-1)/k; ll front; if(l%k==0)front=l; else front=(k-l%k)+l; ll rear=r-r%k; return (front+rear)*num/2; } ll gao(ll l,ll r,ll n){ vector <ll> v; for(ll i=2;i*i<=n;i++){ if(n%i==0){ v.push_back(i); while(n%i==0)n/=i; } } if(n>1)v.push_back(n); int m=v.size(); ll res=0; for(int i=1;i<(1<<m);i++){ int cnt=0; ll val=1; for(int j=0;j<m;j++){ if(i&(1<<j)){ cnt++; val*=v[j]; } } if(cnt&1)res+=sum(l,r,val); else res-=sum(l,r,val); } return (l+r)*(r-l+1)/2-res; } map <ll,ll> mp; map <ll,ll>::iterator it; ll gan(ll x,ll y,ll p){ ll res=gao(x,y,p); for(it=mp.begin();it!=mp.end();it++){ if(it->first>y || it->first<x)continue; if(gcd(it->first,p)==1)res-=it->first; if(gcd(it->second,p)==1)res+=it->second; } return res; } int main(){ int T; scanf("%d",&T); while(T--){ int n,m; scanf("%d%d",&n,&m); mp.clear(); while(m--){ int op; scanf("%d",&op); ll x,y,p; if(op==1){ scanf("%I64d%I64d%I64d",&x,&y,&p); if(x>y)swap(x,y); printf("%I64d\n",gan(x,y,p)); } else{ scanf("%I64d%I64d",&x,&p); mp[x]=p; } } } return 0; }