zoukankan      html  css  js  c++  java
  • 【RMQ】或【线段树】 题目:【Usaco2007 Jan Balanced Lineup排队】 或【飞盘比赛】

     本人水平有限,题解不到为处,请多多谅解

    本蒟蒻谢谢大家观看

    题目:传送门

    Problem E: 飞盘比赛

    Time Limit: 1 Sec  Memory Limit: 128 MB
    Submit: 176  Solved: 126
    [Submit][Status][Web Board]

    Description

    每天, Cici 的N(1 <= N <= 50,000)头学生排成一行. 有一天, Cici 决定让一些学生们玩一场飞盘比赛. 他准备
    找一群在对列中为置连续的学生来进行比赛. 但是为了避免比赛没有悬念,学生的身高不应该相差太大. Cici 准备
    了Q (1 <= Q <= 180,000) 个可能的学生的选择和所有学生的身高 (1 <= 身高 <= 1,000,000). 他想知道每一组
    里面最高和最低的学生的身高差别. 注意: 在最大数据上, 输入和输出将占用大部分运行时间.

    Input

    * 第一行: N 和 Q. * 第2..N+1行: 第i+1行是第i个学生的身高.
    * 第N+2..N+Q+1行: 两个整数, A 和 B (1 <= A <= B <= N), 表示从A到B的所有学生.

    Output

    *第1..Q行: 所有询问的回答 (最高和最低的学生的身高差), 每行一个.

    Sample Input

    6 3
    1
    7
    3
    4
    2
    5
    1 5
    4 6
    2 2

    Sample Output

    6
    3
    0

    HINT

    RMQ模板 或 线段树模板

    code: 

    法一:RMQ

    #include<bits/stdc++.h>
    #pragma GCC optimize(3)
    using namespace std;
    int n,Q;
    int a[180001];
    int l,r,ans;
    int f[180001][21],g[180001][21],len[180001];
    //f 取最大值, g 取最小值 
    //因为 2^21=2097152 > 180001 所以第二维只需要取到21 
    inline int read(){
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    //RMQ的初始化过程 (建树) 
    void build(){
        for(int i=1;i<=n;i++){
            f[i][0]=a[i];//本身最大值为本身 
            g[i][0]=a[i];//同理 :最小值也为本身 
        }
        len[0]=1;
        for(int i=1;i<=21;i++)
            len[i]=len[i-1]*2;//计算2^x 预处理 
        for(int i=n;i>=1;i--){//必须写逆循环 因为下面 j== 1~2^1+n-1 …… 
            for(int j=1;len[j]+i-1<=n;j++){// 求区间 i~i+2^j-1 
                f[i][j]=max(f[i][j-1],f[i+len[j-1]][j-1]); 
                g[i][j]=min(g[i][j-1],g[i+len[j-1]][j-1]);
                //i~i+2^(j-1)-1 与 i+2^(j-1)~i+2^(j-1)+2^(j-1)-1
                //即:i~i+2^j-1
            }
        }
        return ;
    }
    //RMQ查询过程 
    int query(int x,int y){
        int k=log2(y-x+1);//求区间x~y 满足 2^k<=y-x+1,并且使 k 最大 
        int maxx=max(f[x][k],f[y-(1<<k)+1][k]);
        int minn=min(g[x][k],g[y-(1<<k)+1][k]);
        //当 x=1 , y=9 时,k=3;
        //f[x][k] →(x) ~ (x)+(2^k-1) 如:1~8;
        //f[y-(1<<k)+1][k] →(y-2^k+1) ~ (y-2^k+1)+(2^k-1) 如:2~9;
        //在 (1~8 的最值) 与  (2~9 的最值) 之间比较即可 
        return maxx-minn;    
    }
    int main(){
        n=read();Q=read();
        for(int i=1;i<=n;i++)
            a[i]=read();
        build();
        for(int i=1;i<=Q;i++){    
            l=read(),r=read();
            ans=query(l,r);
            printf("%d
    ",ans);
        }
        return 0;
    }

    code:
    法二:线段树

    #pragma GCC optimize(3)
    #include<bits/stdc++.h>
    #define maxn 100000
    using namespace std;
    int n,m,k,x,y;
    int a[maxn];
    inline int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')
            f=-1;
            ch=getchar();
        }
        while(ch<='9'&&ch>='0')
        {
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    struct segment
    { 
        int sum[4*maxn],sum2[4*maxn],ans1,ans2;
        segment()
        {
            memset(sum,-63,sizeof(sum));
            memset(sum2,-63,sizeof(sum2));
        }
        #define lson (p+p)
        #define rson (p+p+1)
        void update(int p)
        {
            sum[p]=max(sum[lson],sum[rson]);
            sum2[p]=min(sum2[lson],sum2[rson]);
        }//求和 
        void build(int p,int l,int r)
        {
            if(l==r)
            {
                sum[p]=a[l];
                sum2[p]=a[l];
                return;
            }
            int mid=(l+r)/2;
            build(lson,l,mid);
            build(rson,mid+1,r);
            update(p);
        } 
        void change(int p,int l,int r,int x,int v)
        {
            if(l==r&&x==l)
            {
                sum[p]+=v;
                return;
            }
            int mid=(l+r)/2;
            if(x<=mid)change(lson,l,mid,x,v);
            if(x>mid)change(rson,mid+1,r,x,v);
            update(p);
        }//把a[x]修改成v
        int querymax(int p,int l,int r,int x,int y)
        {
            if(x<=l&&r<=y)
            {
                return sum[p];
            }
            int mid=(l+r)/2,ans1=-1e9;
            if(x<=l&&y>=r)return ans1=max(ans1,sum[p]);
            if(x<=mid)ans1=max(ans1,querymax(lson,l,mid,x,y));
            if(y>mid)ans1=max(ans1,querymax(rson,mid+1,r,x,y));
            update(p);
            return ans1;
        }//查询x,y区间和 
        int querymin(int p,int l,int r,int x,int y)
        {
            if(x<=l&&r<=y)
            {
                return sum2[p];
            }
            int mid=(l+r)/2,ans2=1e9;
            if(x<=l&&y>=r)return ans2=min(ans2,sum2[p]);
            if(x<=mid)ans2=min(ans2,querymin(lson,l,mid,x,y));
            if(y>mid)ans2=min(ans2,querymin(rson,mid+1,r,x,y));
            update(p);
            return ans2;
        }//查询x,y区间和 
    }kd; 
    int main()
    {
        n=read(); 
        m=read(); 
        for(int i=1;i<=n;i++)a[i]=read(); 
        kd.build(1,1,n);
        for(int i=1,a,b;i<=m;i++)
        {
            a=read();
            b=read(); 
            printf("%d
    ",kd.querymax(1,1,n,a,b)-kd.querymin(1,1,n,a,b));
        }
        return 0;
    }

    其实RMQ数据结构类似于线段树 

    只需要使用一些特殊值方法,基本上可以理解

  • 相关阅读:
    扫描线算法模板
    spark submit 常用设置
    networkx 画有向图 使用DiGraph
    超实用的Spark数据倾斜解决
    解决spark中遇到的数据倾斜问题
    TrickBot 恶意木马软件
    windows 打开snappy文件 安装python snappy——还是直接用pip install xx.whl 打包好的安装吧
    解决CentOS删除文件后没有释放磁盘空间(lsof命令)
    Linux 系统下 centOS 7 ipconfig 提示没有安装
    tomcat启动报错org.apache.catalina.LifecycleException: The configured protocol [org.apache.coyote.http...
  • 原文地址:https://www.cnblogs.com/nlyzl/p/11481021.html
Copyright © 2011-2022 走看看