Problem Description
Teacher Mai finds that many problems about arithmetic function can be reduced to the following problem:
Maintain an array a with index from 1 to l. There are two kinds of operations:
1. Add v to ax for every x that gcd(x,n)=d.
2. Query
Input
There are multiple test cases, terminated by a line "0 0".
For each test case, the first line contains two integers l,Q(1<=l,Q<=5*10^4), indicating the length of the array and the number of the operations.
In following Q lines, each line indicates an operation, and the format is "1 n d v" or "2 x" (1<=n,d,v<=2*10^5,1<=x<=l).
Output
For each case, output "Case #k:" first, where k is the case number counting from 1.
Then output the answer to each query.
Sample Input
6 4 1 4 1 2 2 5 1 3 3 3 2 3 0 0
Sample Output
Case #1: 6 7
Source
2014 Multi-University Training Contest 8
#include <cstdio> #include <vector> using namespace std; long long node[50005]; int mu[200001],prime[200001],l,Q; bool check[200001]; vector<int>fact[200001]; void Mobius() { int i,j,cnt; cnt=0; mu[1]=1; for(i=2;i<=200000;i++) { if(!check[i]) { prime[cnt++]=i; mu[i]=-1; } for(j=0;j<cnt;j++) { if(i*prime[j]>200000) break; check[i*prime[j]]=1; if(i%prime[j]) mu[i*prime[j]]=-mu[i]; else break; } } for(i=1;i<=200000;i++) for(j=i;j<=200000;j+=i) fact[j].push_back(i);//求因子 } void add(int x,int v) { while(x<=l) { node[x]+=v; x+=x&-x; } } long long sum(int x) { long long res=0; while(x>0) { res+=node[x]; x-=x&-x; } return res; } int main() { int cases=1,t,n,d,v,i,last; long long ans,temp,lasttemp; Mobius(); while(scanf("%d%d",&l,&Q) && l) { for(i=0;i<=l;i++) node[i]=0; printf("Case #%d:\n",cases++); while(Q--) { scanf("%d",&t); if(t==1) { scanf("%d%d%d",&n,&d,&v); if(n%d) continue; n/=d; for(i=0;i<fact[n].size();i++) { t=fact[n][i]; add(t*d,mu[t]*v); } } else { scanf("%d",&n); ans=0; temp=0; for(i=1;i<=n;i=last+1) { last=n/(n/i); lasttemp=temp;//分块加速 temp=sum(last); ans+=n/i*(temp-lasttemp); } printf("%I64d\n",ans); } } } }
HDU-4947-GCD Array(树状数组+莫比乌斯反演)