HDU-4947-GCD Array(樹狀數組+莫比烏斯反演)

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


#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);
            }
        }
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章