hdu 4630 No Pain No Game【线段树 离线操作】

No Pain No Game

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 1820    Accepted Submission(s): 778

链接:hdu 4630


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 a 1, a 2, ..., a n.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 1, a 2, ..., a n.
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
      
      
1 10 8 2 4 9 5 7 10 6 1 3 5 2 10 2 4 6 9 1 4 7 10
 
Sample Output
      
      
5 2 2 4 3
 

题意

给定N个数,这N个数是1~N的一种排列,然后给定Q个询问,每次询问一个区间[l,r],在[l,r]这个区间中求最大的gcd(a,b) , {l<=a<=b<=r}。

分析

这里我链接一个大牛的题解,我觉得他的题解讲得挺好的。我这里只补充一句,hdu有组数据是肯定错了,

1

1

1

1   1

正确答案是1才对。然而,杭电的数据确实0。。。

害得我WA了几个小时却不得其解。悲剧,呜呜呜~~~~~

 

/****************************>>>>HEADFILES<<<<****************************/
#include <set>
#include <map>
#include <list>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <algorithm>
using namespace std;
/****************************>>>>>DEFINE<<<<<*****************************/
#define fst             first
#define snd             second
#define root            1,N,1
#define lrt             rt<<1
#define rrt             rt<<1|1
#define lson            l,mid,rt<<1
#define rson            mid+1,r,rt<<1|1
#define PB(a)           push_back(a)
#define MP(a,b)         make_pair(a,b)
#define CASE(T)         for(scanf("%d",&T);T--;)
#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const int maxn = 50000 + 5;
/****************************>>>>SEPARATOR<<<<****************************/
struct Node
{
    int l, r, id;
    Node() {}
    Node(int _l, int _r, int _id) : l(_l), r(_r), id(_id) {}
    bool operator < (const Node& p) const
    {
        return r < p.r;
    }
};
vector<Node> Asks;
int T, N, Q;
int a[maxn], pre[maxn], ans[maxn], segtree[maxn << 2];
vector<int> factor[maxn];
void init()
{
    for(int i = 1; i < maxn; i++)
        for(int j = i; j < maxn; j += i)
            factor[j].PB(i);
}
inline void PushUp(const int& rt)
{
    segtree[rt] = max(segtree[lrt], segtree[rrt]);
}
void Update(const int& pos, const int& val, int l, int r, int rt)
{
    if(l == r)
    {
        segtree[rt] = max(segtree[rt], val);
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) Update(pos, val, lson);
    else Update(pos, val, rson);
    PushUp(rt);
}
int Query(const int& L, const int& R, int l, int r, int rt)
{
    if(L <= l && r <= R)
    {
        return segtree[rt];
//        return max(1, segtree[rt]); 难道两个数的最大公约数不是一定大于1的么???下同
    }
    int mid = (l + r) >> 1, ret = 0; //1; 同上
    if(L <= mid) ret = max(ret, Query(L, R, lson));
    if(R > mid) ret = max(ret, Query(L, R, rson));
    return ret;
}
int main()
{
//    FIN;
    init();
    CASE(T)
    {
        scanf("%d", &N);
        for(int i = 1; i <= N; i++) scanf("%d", &a[i]);
        scanf("%d", &Q);
        Asks.clear();
        for(int i = 1, l, r; i <= Q; i++)
        {
            scanf("%d %d", &l, &r);
            Asks.PB(Node(l, r, i));
        }
        sort(Asks.begin(), Asks.end());
        memset(pre, -1, sizeof(pre));
        memset(segtree, 0, sizeof(segtree));
        int cnt = 0;
        for(int i = 1; i <= N; i++)
        {
            for(int j = 0; j < factor[a[i]].size(); j++)
            {
                int &f = factor[a[i]][j];
                if(pre[f] != -1)
                {
                    Update(pre[f], f, root);
                }
                pre[f] = i;
            }
            while(cnt < Q && Asks[cnt].r == i)
            {
                int &l = Asks[cnt].l, &r = Asks[cnt].r, &id = Asks[cnt].id;
                ans[id] = Query(l, r, root);
                cnt++;
            }
            if(cnt >= Q) break;
        }
        for(int i = 1; i <= Q; i++) printf("%d\n", ans[i]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值