hdu-4630-No Pain No Game-(树状数组,离线处理)

来源:互联网 发布:免费源码加密 编辑:程序博客网 时间:2024/05/29 10:07

Problem Description
Life is a game,and you lose it,so you suicide.
But you can not kill yourself before you solve this problem:
Given you a sequence of number a1, a2, ..., an.They are also a permutation of 1...n.
You need to answer some queries,each with the following format:
If we chose two number a,b (shouldn't be the same) from interval [l, r],what is the maximum gcd(a, b)? If there's no way to choose two distinct number(l=r) then the answer is zero.
 

Input
First line contains a number T(T <= 5),denote the number of test cases. Then follow T test cases. For each test cases,the first line contains a number n(1 <= n <= 50000). The second line contains n number a[sub]1[/sub], a[sub]2[/sub], ..., a[sub]n[/sub]. The third line contains a number Q(1 <= Q <= 50000) denoting the number of queries. Then Q lines follows,each lines contains two integer l, r(1 <= l <= r <= n),denote a query.
 

Output
For each test cases,for each query print the answer in one line.
 

Sample Input
1108 2 4 9 5 7 10 6 1 352 102 46 91 47 10
 

Sample Output
52243

参考大神kuangbin的文章:http://www.cnblogs.com/kuangbin/archive/2013/07/30/3225627.html

题目给出n个数的序列,这个序列是1~n的一个全排列,然后查询是给出一个区间[l,r],让求出区间内任意两个数的最大公约数中的最大值。

让求区间内的gcd的最大值,可以求出区间内的所有数的约数,而那个最大的且是至少两个数的公约数的数就是这个区间的最大gcd,可以用树状数组存放

代码:

//tree[i]是i处的最大约数#include<iostream>#include<string>#include<cstdio>#include<algorithm>#include<cmath>#include<iomanip>#include<queue>#include<cstring>#include<map>using namespace std;#define M 50005int n;int tree[M];int a[M],b[M];int ans[M];struct node {    int l,r,id;    bool operator < (const node &obj) const    {        return l>obj.l;    }}p[M];inline int lowbit(int i){    return i&(-i);}void add(int i,int v){    while(i<=n)    {        tree[i]=max(tree[i],v);        i+=lowbit(i);    }}int sum(int i){    int res=-1;    while(i>0)    {        res=max(res,tree[i]);        i-=lowbit(i);    }    return res;}int main(){    int T,i,j,m;    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);        for(i=1;i<=n;i++)        {            scanf("%d",&a[i]);        }        scanf("%d",&m);        for(i=1;i<=m;i++)        {            scanf("%d%d",&p[i].l,&p[i].r);            p[i].id=i;        }        sort(p+1,p+1+m); //对区间按照l从大到小排序,        memset(tree,0,sizeof(tree));        memset(b,0,sizeof(b));        i=n; j=1;        while(j<=m) //处理区间        {            while(i>0&&i>=p[j].l) //循环点            {                for(int k=1;k*k<=a[i];k++) //找到a[i]的每一个约数,不断更新tree使其中存的是最大的约数                {                    if(a[i]%k==0)                    {                        if(b[k]!=0) //k不是第一次出现,也就是保证k至少是两个数的约数                        {                            add(b[k],k);                        }                        b[k]=i;                        if(k!=a[i]/k)                        {                            if(b[a[i]/k]!=0)                            {                                add(b[a[i]/k],a[i]/k);                            }                            b[a[i]/k]=i;                        }                    }                }                i--;            }            while(j<=m&&p[j].l>i)            {                ans[p[j].id]=sum(p[j].r);                j++;            }        }        for(i=1;i<=m;i++)            printf("%d\n",ans[i]);    }    return 0;}



原创粉丝点击