zoukankan      html  css  js  c++  java
  • poj 3264 Balanced Lineup

    Balanced Lineup

    题意:N cows (1 ≤ N ≤ 50,000)Q (1 ≤ Q ≤ 200,000)queries;每次查询一个区间[l,r];问区间中最高和最矮的牛相差多少?

    本题适合ST的入门题;

    讲讲对ST的简单用法的理解:ST是一个二维DP倍增的思想,二维[i][j]表示区间长度为(1<<j)但是由于包括区间端点,所以表示为 [i,i+(2^j)-1];这时要得到一个长度为2^j的区间的最值,需要建立在子结构[i][j-1]与[i+(1<<j-1)][j-1]的基础之上;这也就是DP思想了;编写程序时,可知要对每一个长度枚举左端点,就构成了两重循环;外层为最大区间长度的数位bin;

    ST算法的时间复杂度是O(nlogn);logn就是n的二进制;同时对里层n的枚举;

    ps:或许看其他人的ST的init()里层的循环是逆着递减的,但是我写的是正常的从1开始递增;其他人的想法是当枚举的位置i加上长度超出序列长度时得到的值就是该点后面数值的全部信息;但是是否需要这样呢。因为我们的查询O(1)是从左右边界相向覆盖;

    这就要看查询时每个端点延伸的长度是否会大于总查询长度的1/2;(显然如果小于1/2那么为什么要出边界呢)同时看看query()就会知道查询时左右端点的覆盖长度几乎等于查询区间的长度,所以这不是必要的~~

    8736K  875MS(有点慢)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string.h>
    #include<algorithm>
    #include<map>
    #include<queue>
    #include<vector>
    #include<cmath>
    #include<stdlib.h>
    #include<time.h>
    #include<stack>
    #include<set>
    using namespace std;
    #define rep0(i,l,r) for(int i = (l);i < (r);i++)
    #define rep1(i,l,r) for(int i = (l);i <= (r);i++)
    #define rep_0(i,r,l) for(int i = (r);i > (l);i--)
    #define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
    #define MS0(a) memset(a,0,sizeof(a))
    #define MS1(a) memset(a,-1,sizeof(a))
    #define inf 0x3f3f3f3f
    typedef __int64 ll;
    template<typename T>
    void read1(T &m)
    {
        T x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        m = x*f;
    }
    template<typename T>
    void read2(T &a,T &b){read1(a);read1(b);}
    template<typename T>
    void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);}
    template<typename T>
    void out(T a)
    {
        if(a>9) out(a/10);
        putchar(a%10+'0');
    }
    const int MAXN = 50050;
    int a[MAXN],mn[MAXN][20],mx[MAXN][20];
    void init(int n)
    {
        int bin = int(log(1.*n)/log(2.0));//bin表示的数位<=精确值
        rep1(i,1,n) mn[i][0] = mx[i][0] = a[i];
        rep1(i,1,bin){
            rep1(j,1,n){ // [j,j + (2^i)-1]
                if(j+(1<<i)-1> n) break;
                mx[j][i] = max(mx[j][i-1],mx[j+(1<<i-1)][i-1]);
                mn[j][i] = min(mn[j][i-1],mn[j+(1<<i-1)][i-1]);
            }
        }   
    }
    int query(int l,int r)
    {
        int bin = int(log(1.*(r-l+1))/log(2.0));
        int m = max(mx[l][bin],mx[r-(1<<bin)+1][bin]);//O(1)的查找
        int n = min(mn[l][bin],mn[r-(1<<bin)+1][bin]);
        return m - n;
    }
    int main()
    {
        int N,Q;
        while(scanf("%d%d",&N,&Q) == 2){
            rep1(i,1,N)
                read1(a[i]);
            init(N);
            int l,r;
            while(Q--){
                read2(l,r);
                out(query(l,r));
                puts("");
            }
        }
        return 0;
    }
    View Code

     使用线段树也做了一下 1716K 719MS

    线段树由于不是O(1)的查询,所以不能直接在每个区间中直接返回mx-mn,这是子区间的最优解,就完全不是整个区间的最优解了;所以要保存每个区间的MX和MN;

    同时线段树不需要判断各种边界(对ST不熟..),觉得写起来更顺畅;

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string.h>
    #include<algorithm>
    #include<map>
    #include<queue>
    #include<vector>
    #include<cmath>
    #include<stdlib.h>
    #include<time.h>
    #include<stack>
    #include<set>
    using namespace std;
    #define rep0(i,l,r) for(int i = (l);i < (r);i++)
    #define rep1(i,l,r) for(int i = (l);i <= (r);i++)
    #define rep_0(i,r,l) for(int i = (r);i > (l);i--)
    #define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
    #define MS0(a) memset(a,0,sizeof(a))
    #define MS1(a) memset(a,-1,sizeof(a))
    #define inf 0x3f3f3f3f
    #define lson l, m, rt << 1
    #define rson m+1, r, rt << 1|1
    typedef __int64 ll;
    template<typename T>
    void read1(T &m)
    {
        T x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        m = x*f;
    }
    template<typename T>
    void read2(T &a,T &b){read1(a);read1(b);}
    template<typename T>
    void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);}
    template<typename T>
    void out(T a)
    {
        if(a>9) out(a/10);
        putchar(a%10+'0');
    }
    const int MAXN = 50050;
    int mx[MAXN<<2],mn[MAXN<<2];
    void pushup(int rt)
    {
        mx[rt] = max(mx[rt<<1],mx[rt<<1|1]);
        mn[rt] = min(mn[rt<<1],mn[rt<<1|1]);
    }
    void build(int l,int r,int rt)
    {
        if(l == r){
            read1(mx[rt]);
            mn[rt] = mx[rt];
            return ;
        }
        int m = l+r>>1;
        build(lson);
        build(rson);
        pushup(rt);
    }
    int MX,MN;
    void query(int L,int R,int l,int r,int rt)
    {
        if(L <= l && r <= R){
            MX = max(MX, mx[rt]);
            MN = min(MN, mn[rt]);
            return ;
        }
        int m = l+r>>1;
        if(L <= m) query(L,R,lson);
        if(m < R) query(L,R,rson);
    }
    int main()
    {
        int N,Q;
        while(scanf("%d%d",&N,&Q) == 2){
            build(1,N,1);
            int l,r;
            while(Q--){
                read2(l,r);
                MX = 0,MN = inf;
                query(l,r,1,N,1);
                out(MX - MN);
                puts("");
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    跳转网页
    在代码插入图像的位置
    图像宽度和高度
    添加图像
    指向同一网站中其中的页面的链接
    指向其他网站的链接
    嵌套列表
    定义
    LeetCode561 数组拆分 I
    LeetCode344 反转字符串
  • 原文地址:https://www.cnblogs.com/hxer/p/5192937.html
Copyright © 2011-2022 走看看