愿各位程序员都能记住,输出第一条hello world时候的心情。坚持下去,你的每一条代码都在默默的改变世界,加油!加油!加油! “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。 什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。 人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。

【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\n",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\n",kd.querymax(1,1,n,a,b)-kd.querymin(1,1,n,a,b));
    }
    return 0;
}

 

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

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

posted @ 2019-09-07 15:20  max_lemon  阅读(127)  评论(4编辑  收藏  举报
Live2D
别人恋爱不成功,你连暗恋都不成功! 你写不出代码的原因只有一个,那就是你没有彻底理解这个算法的思想!!-----沃茨·基硕德