2013 多校第三场 hdu 4630 No Pain No Game(线段树)

hdu 4630

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4630

题目大意:1~n,总共个数,任意顺序排列,然后给你m个询问,每个询问有a、b,问你区间a~b的数里面最大gcd是多少(区间内任意两个数都行)。

思路:由于它问的是gcd,那么我们可以先枚举约数,即1~n,对于每个约数去画区间,我们要求的是对于每个区间长度要尽可能的小,比如约数是1的区间,那就是两两相邻的数下面都要画一条1。这里很巧妙地用了一个pre数组,pre[ i ] 表示数字i在当前位置之前,i的倍数,出现的最靠右的位置,也就是在pre[ i ] 和当前位置之前画一条val值为i的线(当前值为i的倍数)。因为只有当询问覆盖整条线时,这条线的val值才有效,而我们处理的查询右端点是一样的,所以我们把线的值全都放在左端点,把所有的询问按照右端点排序,然后从左往右扫过去。用线段树维护,遇到是右端点,直接查询即可。

这里还有一些细节问题,我们可以先把每个数对应的因数全找出来。然后扫到第i个数字值为x,遍历一遍它的所有因子,看看pre[ t ] 有没有,有的话直接更新线段树,然后再更新pre[ t ] =i 。如果用树状数组的话,由于它不能直接查询指定区间的最大值,我们只要查询的是pre[ t ] 到当前处理到的位置i的最大值,这里有一个技巧,对于每个数,本来更新位置在pre[ t ],把它变成 n-pre[ t ] +1,也就是将本来的区间对称了一下,这样就能按照原本的方式查询了,查询的位置是 n-l+1(l是询问的左端点)。试了一下,发现线段树比树状数组慢了一倍。。 = =

比赛的时候,知道这种题目肯定是线段树,可就是想不出来该怎样构建。。 枚举约数、区间、从左往右扫,左端点、离线,哎,神段树啊,慢慢积累吧。。

先是树状数组的,代码如下:

#include
#include
#include
#include
using namespace std;

const int MAXN = 55555 ;

int num[MAXN];

struct Qu
{
    int l,r;
    int id;
    bool operator < (const Qu &tmp) const
    {
        return r factor[MAXN];

int n;

void get_factor()
{
    for(int i=1;i<=n;i++)
        factor[i].clear();
    for(int i =1;i0)
    {
        maxx = max(node[pos],maxx);
        pos -= lowbit(pos);
    }
    return maxx;
}

int ans[MAXN];

int pre[MAXN];

int main()
{
    get_factor();
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i = 1;i<=n;i++)
        {
            scanf("%d",&num[i]);
        }
        int m;
        scanf("%d",&m);
        for(int  i =1;i<=m;i++)
        {
            scanf("%d%d",&qu[i].l,&qu[i].r);
            qu[i].id = i;
        }
        sort(qu+1,qu+1+m);

        memset(pre,0,sizeof(pre));
        int k = 1;
        init_tree();
        for(int i = 1;i<=n;i++)
        {
            int cur = num[i];
            for(int j = 0;j


然后是线段树的(其实就改了一下下):

#include
#include
#include
#include
using namespace std;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

const int MAXN = 55555 ;

int num[MAXN];

struct Qu
{
    int l,r;
    int id;
    bool operator < (const Qu &tmp) const
    {
        return r factor[MAXN];

int n;

void get_factor()
{
    for(int i=1;i<=n;i++)
        factor[i].clear();
    for(int i =1;i>1;
    if(pos<=m) update(lson,pos,c);
    else update(rson,pos,c);
    node[rt] = max(node[rt<<1],node[rt<<1|1]);
}

int query(int l,int r,int rt,int a,int b)
{
    if(a<=l&&b>=r)
    {
        return node[rt];
    }
    int m = l+r>>1;
    int cnt1 = 0,cnt2 = 0;
    if(a<=m) cnt1 = query(lson,a,b);
    if(b>m) cnt2 = query(rson,a,b);
    return max(cnt1,cnt2);
}

int ans[MAXN];

int pre[MAXN];

int main()
{
    get_factor();
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i = 1;i<=n;i++)
        {
            scanf("%d",&num[i]);
        }
        int m;
        scanf("%d",&m);
        for(int  i =1;i<=m;i++)
        {
            scanf("%d%d",&qu[i].l,&qu[i].r);
            qu[i].id = i;
        }
        sort(qu+1,qu+1+m);

        memset(pre,0,sizeof(pre));
        int k = 1;
        init_tree();
        for(int i = 1;i<=n;i++)
        {
            int cur = num[i];
            for(int j = 0;j


你可能感兴趣的:(数据结构,2013暑期集训)