HDU - 4630 No Pain No Game(离线线段树)

No Pain No Game

题意:给出一个长度为n的1到n的排列 求区间两点gcd最大

思路:

因为题目没有更新 我们可以离线求解

对于每个查询按r排序

因为两点gcd一定会是两个数的约数 那么可以暴力插入a[i]的约数(当a[x]含有这个约数时 我们就能插入这个约数(x<i))

我们使用last数组维护上一次出现这个约数的位置即可

查询:我们就只需要查询l~r出现过最大的约数就行

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define inf 0x3f3f3f3f
const int maxn = 50000+5;
int Max[maxn<<2],a[maxn],last[maxn],ans[maxn];
struct node{
    int l,r,id;
    bool friend operator<(const node u,const node v){
        return u.r<v.r;
    }
}p[maxn];
void build(int l,int r,int rt){
    Max[rt]=0;
    if(l==r) return ;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
void push_up(int rt){
    Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}
void update(int l,int r,int rt,int L,int val){
    if(l==r){
        Max[rt]=max(Max[rt],val);
        return ;
    }
    int m=(l+r)>>1;
    if(L<=m) update(lson,L,val);
    else update(rson,L,val);
    push_up(rt);
}
int query(int l,int r,int rt,int L,int R){
    if(L<=l&&r<=R) {
        return Max[rt];
    }
    int m=(l+r)>>1;
    int ans=0;
    if(L<=m) ans=max(ans,query(lson,L,R));
    if(R>m)  ans=max(ans,query(rson,L,R));
    return ans;
}
int main(){
    int t,n,m;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        memset(last,0,sizeof(last));
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%d %d",&p[i].l,&p[i].r);
            p[i].id=i;
        }
        sort(p+1,p+1+m);
        int j=1;
        build(1,n,1);
        for(int i=1;i<=n;i++){
            for(int k=1;k*k<=a[i];k++){
                if(a[i]%k==0){
                    if(last[k])
                        update(1,n,1,last[k],k);
                    if(last[a[i]/k]&&k!=a[i]/k)
                        update(1,n,1,last[a[i]/k],a[i]/k);
                    last[k]=i;
                    last[a[i]/k]=i;
                }
            }
            while(p[j].r<=i){
                if(j>m) break;
                if(p[j].l>p[j].r) ans[p[j].id]=0;
                else ans[p[j].id]=query(1,n,1,p[j].l,p[j].r);
                j++;
            }
        }
        for(int i=1;i<=m;i++){
            printf("%d\n",ans[i]);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/MengX/p/11291349.html

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

HDU - 4630 No Pain No Game(离线线段树)的相关文章

HDU 4630 No Pain No Game(线段树离线处理)

题目链接:点击打开链接 题意:给你一个n的全排列, q个操作, 每个操作是一个区间,要求求出这个区间中任意两个数的gcd的最大值. 思路:一个数是两个数的公约数, 等价于一个数可以被两个整数同时整除.   所以我们可以算出每一个数的所有约数, 然后求一个区间中被超过两个数整除的数中的最大值即可. 维护区间最大值, 我们可以用线段树来维护.  因为我们难以同时维护一个区间, 所以我们离线处理, 按照r排序, 那么每次如果当前数的一个约数曾经出现过, 就在之前出现的点加入线段树, 每次顺便查询即可.

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 y

hdu 4638 Group(莫队算法|离线线段树)

Group Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1323    Accepted Submission(s): 703 Problem Description There are n men ,every man has an ID(1..n).their ID is unique. Whose ID is i and i-

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

HDU 4417 Super Mario(离线线段树or树状数组)

Problem Description Mario is world-famous plumber. His "burly" figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble again and Mario needs to save his lover. We regard the road to the boss's castle as a l

HDU ACM 4417 Super Mario 离线线段树

分析:离线线段树,把所有询问离线读入,然后按H从小到大排序.对于所有结点也按从小到大排序,然后根据查询的H,将比H小的点加入到线段树,最后就是一个区间求和.这题貌似也可以用划分树,树状数组等方法做. #include<iostream> #include<algorithm> using namespace std; #define N 100005 struct Tree { int left,right,cnt; } TREE[N<<2]; struct Query

HDU 5172 GTY&#39;s gay friends (线段树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5172 题意: 给你一个n个数的数组,m次询问,询问在[L, R] 这个区间里面有没有 [1, R-L+1] 的数. 题解: 判断有没有 1 ~ R-L+1 其实就是判断这一段区间和是不是等于 (R-L+1)*(R-L+1+1)/ 2 . 当然还有就是每一个数只能出现1次. 这个问题我们应该怎么解决呢. 我们可以记录第i个数x 的前一个x出现的位置.如果x的前一个x也出现在[L, R]里面,那么这一段

HDU 1540 &amp;&amp; POJ 2892 Tunnel Warfare (线段树,区间合并).

~~~~ 第一次遇到线段树合并的题,又被律爷教做人.TAT. ~~~~ 线段树的题意都很好理解吧.. 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1540 http://poj.org/problem?id=2892 ~~~~ 我的代码:200ms #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #defin

HDU 4027 Can you answer these queries? (线段树+区间点修改)

题意:给你 n 个数,m个询问(c,x,y) c==0 把x,y区间的值变为原来的平方根(向下取整) c==1 计算x,y区间的和. 利用1的开方永远为1剪枝.. #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> //#include<map> #include<cmath> #include<iostream> #include

HDU 4027 Can you answer these queries?(线段树,区间更新,区间查询)

题目 线段树 简单题意: 区间(单点?)更新,区间求和 更新是区间内的数开根号并向下取整 这道题不用延迟操作 //注意: //1:查询时的区间端点可能前面的比后面的大: //2:优化:因为每次更新都是开平方,同一个数更新有限次数就一直是1了,所以可以这样优化 #include <stdio.h> #include<math.h> #define N 100010 #define LL __int64 #define lson l,m,rt<<1 #define rson