题意:
有两种操作1,2
1:询问 x,y区间能与p互质的数的和
2:将x改成p
一开始给N,初始是1~N个数
思路:
我们在求不互质的数有多少个的时候 其实就可以用等差数列求和求出这些数的和
那么我们到时候直接求一下就好了
然后因为这里的操作次数很少 所以我们可以标记一下哪些位置被修改过
然后在1操作的时候 特判一下这些位置
代码:
#include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #include"algorithm" #include"iostream" using namespace std; #define ll __int64 #define N 400000 int ss[N+2],v[N+2]; int mark[N+5][10],mcnt[N+5],c[10]; int used[N+5],change[N+5]; int n,chacnt; int gcd(int a,int b) { return b==0?a:gcd(b,a%b); } int ssb() { int cnt=0; memset(ss,0,sizeof(ss)); for(int i=2;i<=N;i++) { if(ss[i]==0) { for(int j=i+i;j<=N;j+=i) ss[j]=1; v[cnt++]=i; } } return cnt; } ll dfs(int k,int t,int lit,ll x,ll y,int p) { ll ans=0; if(t==lit) { ll tep=1; for(int i=0;i<lit;i++) tep*=c[i]; ll a=(tep+(x-1)/tep*tep)*((x-1)/tep)/2; ll b=(tep+y/tep*tep)*(y/tep)/2; return b-a; } for(int i=k+1;i<mcnt[p];i++) { c[t]=mark[p][i]; ans+=dfs(i,t+1,lit,x,y,p); } return ans; } ll solve(ll x,ll y,int p) { ll ans=0,tep=((1+y)*y/2)-((x)*(x-1)/2); for(int i=1;i<=mcnt[p];i++) { if(i%2) ans+=dfs(-1,0,i,x,y,p); else ans-=dfs(-1,0,i,x,y,p); } ans=tep-ans; for(int i=0;i<chacnt;i++) { if(change[i]>=x&&change[i]<=y) { if(gcd(change[i],p)==1) ans-=change[i]; if(gcd(used[change[i]],p)==1) ans+=used[change[i]]; } } return ans; } int main() { int t,sscnt; cin>>t; sscnt=ssb(); memset(mcnt,0,sizeof(mcnt)); for(int i=0;i<sscnt;i++) { for(int j=v[i];j<=N;j+=v[i]) { mark[j][mcnt[j]++]=v[i]; } } while(t--) { int m; chacnt=0; scanf("%d%d",&n,&m); memset(used,0,sizeof(used)); while(m--) { int f,x,y,p; scanf("%d",&f); if(f==1) { scanf("%d%d%d",&x,&y,&p); printf("%I64d\n",solve(x,y,p)); } else { scanf("%d%d",&x,&p); if(used[x]==0) change[chacnt++]=x; used[x]=p; } } } return 0; }
时间: 2024-10-17 04:05:45