hdu4630 No Pain No Game(离线 线段树)

区间最大公约数求解

借鉴这里:http://blog.youkuaiyun.com/dongdongzhang_/article/details/9670039

有N个数, 是 1~N的一个排列。有M个询问, 每次询问一个区间, 问从这个区间中,取两个数的最大的最大公约数。

首先要求出每个数对应的因子存起来。在一个区间内, 如果一个因子出现两次,该因子就肯定是该区间的一个解。 而出现两次并且是最大。 就是该区间的最优解。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
#define clr(x) memset(x,0,sizeof(x))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define havemid int m=(l+r)>>1
#define left (rt<<1)
#define right (rt<<1|1)
const int maxn=50005;
int sum[maxn<<2];
int a[50005];
void pushup(int rt){
    sum[rt]=max(sum[left],sum[right]);
}
void build(int l,int r,int rt){
    if(l==r){
        sum[rt]=0;
        return ;
    }
    havemid;
    build(lson);
    build(rson);
    pushup(rt);
}
void update(int p,int add,int l,int r,int rt){
    if(l==r){
        sum[rt]=max(sum[rt],add);return ;
    }
    havemid;
    if(p<=m)update(p,add,lson);
    else update(p,add,rson);
    pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
    if(L<=l&&r<=R)return sum[rt];
    havemid;
    int ret=0;
    if(L<=m)ret=query(L,R,lson);
    if(R>m)ret=max(ret,query(L,R,rson));
    return ret;
}
struct node {
    int x,y,id;
}Q[50010];
int cmp(struct node a,struct node b){
    return a.y<b.y;
}
int mp[50010];
int temp[50010][100];
int top[50010];
int res[50010];
int main(){
    int T,n,m,i,j;
    scanf("%d",&T);
    while(T--){
        clr(mp);
        clr(top);
        clr(temp);
        scanf("%d",&n);
        for(i=1;i<=n;i++){
            scanf("%d",&a[i]);
            for(j=1;j*j<=a[i];j++){
                if(a[i]%j==0){
                    temp[i][top[i]++]=a[i]/j;
                    if(j*j!=a[i])temp[i][top[i]++]=j;
                }
            }
        }
        build(1,n,1);
        scanf("%d",&m);
        for(i=0;i<m;i++){
            scanf("%d%d",&Q[i].x,&Q[i].y);
            Q[i].id=i;
        }
        sort(Q,Q+m,cmp);
        int k=0;
        for(i=1;i<=n;i++){
            if(k>=m)break;
            for(j=0;j<top[i];j++){
                int t=temp[i][j];
                if(mp[t]!=0){
                    update(mp[t],t,1,n,1);
                }
                mp[t]=i;
            }
            while(i==Q[k].y){
                res[Q[k].id]=query(Q[k].x,Q[k].y,1,n,1);
                k++;
            }
        }
        for(i=0;i<m;i++){
            printf("%d\n",res[i]);
        }
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值