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

Author

WJMZBMR

Source

2013 Multi-University Training Contest 3

Recommend

zhuyuanchen520   |   We have carefully selected several similar problems for you:  5283 5282 5280 5279 5278

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

题解:先把查询按右区间升序排序,在将数组按顺序插入,记录当前这个数的因子出现的位置,如果之前有出现则代表这两个因子出现的

位置之间有两个数的公共约数是它,用线段树维护区间约数最大值即可。

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#define lson idx<<1,l,mid
#define rson idx<<1|1,mid+1,r
#define N 50050
#define lc idx<<1
#define rc idx<<1|1

using namespace std;

int n,q,flag;
int a[N],tree[N*4];
int L[N],R[N];
int first[N],ans[N];
vector<int>vec;

struct node {
    int id;
    int l,r;
} Q[N];

bool cmp(node a,node b) {
    if(a.r==b.r)
        return a.l<b.l;
    return a.r<b.r;
}

///求所有因子
void FJ(int x) {
    vec.clear();
    for(int i=1; i*i<=x; i++) {
        if(x%i==0) {
            vec.push_back(i);
            if(x/i!=i)
                vec.push_back(x/i);
        }
    }
}

void push_up(int idx) {
    tree[idx]=max(tree[lc],tree[rc]);
}

void build(int idx,int l,int r) {
    tree[idx]=0;
    if(l==r) {
        return;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
}

void update(int idx,int l,int r,int x,int v) { //x处的值改为v
    if(l==r) {
        if(tree[idx]<v)
            tree[idx]=v;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)update(lson,x,v);
    else      update(rson,x,v);
    push_up(idx);
}

int query(int idx,int l,int r,int x,int y) {
    if(l>=x&&y>=r) {
        return tree[idx];
    }
    int ans=0;
    int mid=(l+r)>>1;
    if(x<=mid) {
        ans=max(ans,query(lson,x,y));
    }
    if(y>mid) {
        ans=max(ans,query(rson,x,y));
    }
    return ans;
}

void debug() {
    for(int i=0; i<vec.size(); i++) {
        printf("%d ",vec[i]);
    }
    cout<<endl;
}

int main() {
    //freopen("test.in","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--) {
        scanf("%d",&n);
        for(int i=1; i<=n; i++) {
            scanf("%d",&a[i]);
        }
        scanf("%d",&q);
        for(int i=1; i<=q; i++) {
            scanf("%d%d",&Q[i].l,&Q[i].r);
            Q[i].id=i;
        }
        sort(Q+1,Q+1+q,cmp);
        memset(first,0,sizeof first);
        memset(L,0,sizeof L);
        memset(R,0,sizeof R);
        build(1,1,n);
        ///预处理相同有区间的左右区间
        int f=1;
        L[Q[f].r]=f;
        R[Q[f].r]=f;
        for(int i=1; i<=q;) {
            while(Q[i].r==Q[f].r&&i<=q) {
                i++;
            }
            L[Q[f].r]=f;
            R[Q[f].r]=i-1;
            f=i;
        }
        for(int i=1; i<=n; i++) {
            //FJ(a[i]);
            //debug();
            int xx=a[i];
            for(int k=1; k*k<=xx; k++) {
                if(xx%k==0) {
                    if(!first[k]) {
                        first[k]=i;
                    } else {
                        update(1,1,n,first[k],k);
                        first[k]=i;
                    }
                    int kk=xx/k;
                    if(k!=kk) {
                        if(!first[kk]) {
                            first[kk]=i;
                        } else {
                            update(1,1,n,first[kk],kk);
                            first[kk]=i;
                        }
                    }
                }
            }
            int x=L[i],y=R[i];
            if(x==0||y==0)continue;
            for(int j=x; j<=y; j++) {
                int k=Q[j].l;
                if(k==i) {
                    ans[Q[j].id]=0;
                } else {
                    ans[Q[j].id]=query(1,1,n,k,i);
                }
            }
            if(y==q)break;
        }
        for(int i=1; i<=q; i++) {
            printf("%d\n",ans[i]);
        }
    }
    return 0;
}

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

时间: 2024-10-08 03:59:50

hdu 4630 No Pain No Game(线段树+离线操作)的相关文章

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