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

欢迎参加——每周六晚的BestCoder(有米!)

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 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 a1, a2, ..., an.

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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-13 23:53:13

hdu 4630 No Pain No Game【线段树 离线操作】的相关文章

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): 1769    Accepted Submission(s): 748 Problem Description Life is a game,and you lose it,so you suicide. But you can not kill yours

HDU 4630 No Pain No Game (线段树离线查询)

题目地址:HDU 4630 这题一看数据范围,于是一直在思考n*logn的算法..实在没想到好方法,找了找题解,发现都是用的n*sqrt(n)*logn的方法...算了算,这个复杂度的确可以过..好吧.. 然后就可以先离线下来将询问按r值排序,然后枚举每个数,并且用sqrt(n)的方法枚举所有的约数,然后对于每个约数,对最近的一次出现的这个约数的地方进行更新.因为对于当前区间来讲,只要最近的这个地方更新了,那么前面的查询肯定都能查到这个地方的最大值,所以前面的不用更新. 代码如下: #inclu

hdu 4630 No Pain No Game (线段树+离线)

题目大意:给你一个无序的1~n的排列a,每次询问[l,r]之间任取两个数得到的最大gcd是多少 先对所有询问离线,然后把问题挂在区间的左端点上(右端点也行) 在预处理完质数,再处理一个next数组,表示 i 的任意一个质因子,这样我们分解质因数的时间降低到而不是 因为能对答案产生贡献的都是成对出现的两个数 所以每次记录一个last[i],表示数 i 上一次出现的位置 当遍历到第 i 个数时,分解出它的所有质因数,然后搜出它所有的因子,因子个数大约不会超过,均摊下来就更少了 那么,a[i] 的某个

hdu 4630 No Pain No Game 线段树离线处理

题目链接 求出一个区间内任意两个数的gcd的最大值. 先将询问读进来然后按r值排序. 将每一个数因数分解, 对每一个因子x, 如果pre[x]!=-1, 那么就更新update(pre[x], x, 1, n, 1), 当前的坐标i和某一个询问的r相同时进行查询. 具体看代码.注意l和r相同时答案是0. 初始的时候将maxx数组都弄成1. 谜之WA了n次才发现是数组开小了. #include <iostream> #include <vector> #include <cst

hdu 1394 Minimum Inversion Number(线段树)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 10853    Accepted Submission(s): 6676 Problem Description The inversion number of a given number sequence a1, a2, ..., a

HDU 4902 (牛叉的线段树)

Nice boat Problem Description There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in love and c

HDU Wow! 4893 Such Sequence!(线段树)

HDU 4893 Wow! Such Sequence! 题目链接 题意:给定一个序列,3种操作,单点添加值,查询区间和,把区间和变成最接近的婓波那契数 思路:线段树,就是第三个操作麻烦,就在结点添加一个值,标记它区间是不是都是婓波那契数了,然后修改区间的时候,如果区间是了就不用修改,如果不是就继续往后一层推即可 代码: #include <cstdio> #include <cstring> #include <cstdlib> #define lson(x) ((x

HDU 4893 Wow! Such Sequence! 水线段树

思路: 线段树走起.. 写完这题就退役T^T 单点更新的时候直接找到这个点的最近fib,然后维护当前和 和 fib的和 #include<stdio.h> #include<string.h> #include<iostream> #include<math.h> #include<algorithm> #include<queue> #include<map> #include<set> #include&l

HDU 1754 I Hate It (线段树 单点更新)

题目链接 中文题意,与上题类似. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <cstdlib> 6 #include <algorithm> 7 const int maxn = 200000+10; 8 using namespace std; 9 int a[maxn], n, m; 10

hdu 4893 Wow! Such Sequence!(线段树功能:单点更新,区间更新相邻较小斐波那契数)

转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4893 --------------------------------------------------------------------------------------------------------------------------------------------