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

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(树状数组+莫比乌斯反演)

时间: 2024-07-31 15:30:10

HDU-4947-GCD Array(树状数组+莫比乌斯反演)的相关文章

HDU 3854 Glorious Array(树状数组)

题意:给一些结点,每个结点是黑色或白色,并有一个权值.定义两个结点之间的距离为两个结点之间结点的最小权值当两个结点异色时,否则距离为无穷大.给出两种操作,一种是将某个结点改变颜色,另一个操作是询问当前距离小于K的结点有多少对,K是一个定值. 思路:先求最初时候小于k的结点有多少对,然后每次改变颜色的时候,统计该点左侧和右侧各有多少同色和异色的结点(这一步使用树状数组),分别处理就行.另外需要预处理离某个结点最近的两个距离小于K的结点的位置. 代码写的略乱. #include<cstdio> #

hdu 5869 区间不同GCD个数(树状数组)

Different GCD Subarray Query Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 221    Accepted Submission(s): 58 Problem Description This is a simple problem. The teacher gives Bob a list of probl

HDU 1541 Stars (树状数组)

Problem Description Astronomers often examine star maps where stars are represented by points on a plane and each star has Cartesian coordinates. Let the level of a star be an amount of the stars that are not higher and not to the right of the given

HDU 3333 Turing Tree 树状数组 离线查询

题意: 给你一个数列,然后有n个查询,问你给定区间中不同数字的和是多少. 思路还是比较难想的,起码对于蒟蒻我来说. 将区间按照先右端点,后左端点从小到大排序之后,对于每个查询,我只要维护每个数字出现的最后一次就可以了(这个结论稍微想一下就可以证明是正确的). 然后就是简单的点更新,区间求和问题了- #include <cstdio> #include <cstring> #include <iostream> #include <map> #include

HDU 2689 Sort it (树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2689 Sort it Problem Description You want to processe a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. Then how many times it 

HDU 2492 Ping pong (树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2492 Ping pong Problem Description N(3<=N<=20000) ping pong players live along a west-east street(consider the street as a line segment). Each player has a unique skill rank. To improve their skill rank

HDU 1541 Stars(树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1541 解析: 题意:大概就是计算每颗星星左下边包括了多少颗星星,这个数值就是level.左下边不包括本身,不超过本身的x,y的坐标,可以等于.问每种level有多少颗星星. 这题,一开始想不到怎么用到树状数组,后来看了一下,发现题目给的数据是已经按x,y排好序的,所以我们可以不用管y的值. 注意: 1.每次输入一个坐标对之后,都要计算一下这个它的level. 2.此题的x坐标可以为0,而树状数组是从

HDU 1892 二维树状数组

See you~ Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 3485    Accepted Submission(s): 1103 Problem Description Now I am leaving hust acm. In the past two and half years, I learned so many kno

FZU2224 An exciting GCD problem 区间gcd预处理+树状数组

分析:(别人写的) 对于所有(l, r)区间,固定右区间,所有(li, r)一共最多只会有log个不同的gcd值, 可以nlogn预处理出所有不同的gcd区间,这样区间是nlogn个,然后对于询问离线处理, 用类似询问区间不同数字的方法,记录每个不同gcd最后出现的位置,然后用树状数组进行维护 注:我是看了这段代码会的,但是他的nlogn预处理我不会,我会nlog^2n的 dp[i][j]代表以i为右端点,向左延伸2^j个点(包括i)的gcd,然后因为这样的gcd满足递减,所以可以二分找区间 代