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 problems about GCD (Greatest Common Divisor). After studying some of them, Bob thinks that GCD is so interesting. One day, he comes up with a new problem about GCD. Easy as it looks, Bob cannot figure it out himself. Now he turns to you for help, and here is the problem:
  
  Given an array a of N positive integers a1,a2,?aN−1,aN; a subarray of a is defined as a continuous interval between a1 and aN. In other words, ai,ai+1,?,aj−1,aj is a subarray of a, for 1≤i≤j≤N. For a query in the form (L,R), tell the number of different GCDs contributed by all subarrays of the interval [L,R].

Input

There are several tests, process till the end of input.
  
  For each test, the first line consists of two integers N and Q, denoting the length of the array and the number of queries, respectively. N positive integers are listed in the second line, followed by Q lines each containing two integers L,R for a query.

You can assume that 
  
    1≤N,Q≤100000 
    
   1≤ai≤1000000

Output

For each query, output the answer in one line.

Sample Input

5 3
1 3 4 6 9
3 5
2 5
1 5

Sample Output

6
6
6

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

problem:
给你一组数, 然后是q个查询. 问[l,r]中所有区间GCD的值总共有多少个(不同的)

solve:
感觉很像线段树/树状数组. 因为有很多题都是枚举从小到大处理查询的r. 这样的话就只需要维护[1,i]的情况
最开始用的set记录生成的gcd然后递推, 超时了.
因为区间gcd是有单调性的.  (i-1->1)和i区间gcd是递减的.
而且用RMQ可以O(1)的查询[i,j]gcd的值.如果枚举[1,i-1]感觉很麻烦.所以用二分跳过中间gcd值相同的部分,即查询与i的区间gcd值为x的
最左边端点.

因为要求不同的值, 这让我想到了用线段树求[l,r]中不同数的个数(忘了是哪道题了 zz)
就i而言,首先找出最靠近i的位置使gcd的值为x. 然后和以前的位置作比较. 尽可能的维护这个位置靠右.
假设:
[3,i-1]的gcd为3,[2,i]的gcd为3.  那么在位置3上面加1.因为只要[l,i]包含这个点,那么就会有3这个值.

hhh-2016-09-10 19:01:57
*/
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <stdio.h>
#include <cstring>
#include <vector>
#include <math.h>
#include <queue>
#include <set>
#include <map>
#define ll long long

using namespace std;

const int maxn = 100100;

int a[maxn];
map<ll,int>mp;

struct node
{
    int l,r;
    int id;
} p[maxn];

bool tocmp(node a,node b)
{
    if(a.r != b.r)
        return a.r < b.r;
    if(a.l != b.l)
        return a.l < b.l;
}

ll Gcd(ll a,ll b)
{
    if(b==0) return a;
    else return Gcd(b,a%b);
}

int lowbit(int x)
{
    return x&(-x);
}

ll out[maxn];
ll siz[maxn];

int n;
void add(int x,ll val)
{
    if(x <= 0)
        return ;
    while(x <= n)
    {
        siz[x] += val;
        x += lowbit(x);
    }
}

ll sum(int x)
{
    if(x <=0)
        return 0;
    ll cnt = 0;
    while(x > 0)
    {
        cnt += siz[x];
        x -= lowbit(x);
    }
    return cnt;
}

int dp[maxn][40];
int m[maxn];

int RMQ(int x,int y)
{
    int t = m[y-x+1];
    return Gcd(dp[x][t],dp[y-(1<<t)+1][t]);
}

void iniRMQ(int n,int c[])
{
    m[0] = -1;
    for(int i = 1; i <= n; i++)
    {
        m[i] = ((i&(i-1)) == 0)? m[i-1]+1:m[i-1];
        dp[i][0] = c[i];
    }
    for(int j = 1; j <= m[n]; j++)
    {
        for(int i = 1; i+(1<<j)-1 <= n; i++)
            dp[i][j] = Gcd(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
    }
}

void init()
{
    mp.clear();
    memset(siz,0,sizeof(siz));
    iniRMQ(n,a);
}

int main()
{
    int qry;
    while(scanf("%d",&n) != EOF)
    {
        scanf("%d",&qry);

        for(int i = 1; i<=n; i++)
        {
            scanf("%d",&a[i]);
        }
        init();
        for(int i = 0; i < qry; i++)
        {
            scanf("%d",&p[i].l),scanf("%d",&p[i].r),p[i].id = i;
        }
        int ta = 0;
        sort(p, p+qry, tocmp);

        for(int i = 1; i <= n; i++)
        {
            int thea = a[i];
            int j = i;
            while(j >= 1)
            {
                int tmid = j;
                int l = 1,r = j;

                while(l <= r)
                {
                    int mid = (l+r) >> 1;
                    if(l == r && RMQ(mid,i) == thea)
                    {
                        tmid = mid;
                        break;
                    }

                    if(RMQ(mid,i) == thea)
                        r = mid-1,tmid = mid;
                    else
                        l = mid+1;
                }

                if(!mp[thea])
                    add(j,1);
                else if(mp[thea] < j && mp[thea])
                {
                    add(mp[thea],-1);
                    add(j,1);
                }
                mp[thea] = j;

                j = tmid-1;

                if(j >= 1) thea = RMQ(j,i);
            }

            while(ta < qry && p[ta].r == i)
            {
                out[p[ta].id] = sum(p[ta].r) - sum(p[ta].l-1);
                ta++;
            }

        }

        for(int i = 0; i < qry; i++)
            printf("%I64d\n",out[i]);
    }
    return 0;
}

  

时间: 2024-10-25 13:44:53

hdu 5869 区间不同GCD个数(树状数组)的相关文章

hdu 1166:敌兵布阵(树状数组,练习题)

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 37773    Accepted Submission(s): 15923 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就

hdu 1556 Color the ball(树状数组)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1556 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的"小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色.但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气

hdu 1394 Minimum Inversion Number (裸树状数组 求逆序数)

题目链接 题意: 给一个n个数的序列a1, a2, ..., an ,这些数的范围是0-n-1, 可以把前面m个数移动到后面去,形成新序列:a1, a2, ..., an-1, an (where m = 0 - the initial seqence)a2, a3, ..., an, a1 (where m = 1)a3, a4, ..., an, a1, a2 (where m = 2)...an, a1, a2, ..., an-1 (where m = n-1)求这些序列中,逆序数最少的

【51nod】 第K大区间2(二分+树状数组)

[51nod] 第K大区间2(二分+树状数组) 第K大区间2 ﹡    LH (命题人) 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 160 定义一个长度为奇数的区间的值为其所包含的的元素的中位数.中位数_百度百科 现给出n个数,求将所有长度为奇数的区间的值排序后,第K大的值为多少. 样例解释: [l,r]表示区间的值 [1]:3 [2]:1 [3]:2 [4]:4 [1,3]:2 [2,4]:2 第三大是2 Input 第一行两个数n和k(1<=n<=100000,k&l

HDU 2852 KiKi&#39;s K-Number【 树状数组 二分 】

题意:给出m个操作,0:是增加一个数,add(x,1)1:是删除一个指定的数,这个是看sum(x) - sum(x-1)是否为0,为0的话则不存在,不为0的话,则add(x,-1)2:是查询比x大的数中第k大的数,先求出比x小的个数s,假设比x大的数中第k大的数为y,那么比y小的个数有s+k个二分y的值来找 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include <cmath&g

HDU 5592 ZYB&#39;s Game 【树状数组】+【二分】

<题目链接> 题目大意: 给你一个由1~n,n个数组成的序列,给出他们每个的前缀逆序数,现在要求输出这个序列. 解题分析: 由前缀逆序数很容易能够得到每个数的逆序数.假设当前数是i,它前面比它小的数为a[i]( i - 1 - i的逆序数即可),我们不难知道,i在前i个数中是第i+1大的.然后我们从后往前考虑,每次都能确定一个位置的数的大小,根据当前位置i的数在 1~i 的数的大小,我们用二分查找快速聪当前还未分配的数中给它分配相应大小的数值,然后将这个数值从可分配的数中剔除,防止对前面的数造

hdu 1541/poj 2352:Stars(树状数组,经典题)

Stars Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4052    Accepted Submission(s): 1592 Problem Description Astronomers often examine star maps where stars are represented by points on a plan

hdu 5877 Weak Pair dfs序+树状数组+离散化

Weak Pair Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Problem Description You are given a rooted tree of N nodes, labeled from 1 to N. To the ith node a non-negative value ai is assigned.An ordered pair of no

HDU 1892 See you~ (二维树状数组)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1892 See you~ Problem Description Now I am leaving hust acm. In the past two and half years, I learned so many knowledge about Algorithm and Programming, and I met so many good friends. I want to say so