• 区间的价值(线段树)百度之星


    区间的价值

    Accepts: 0
    Submissions: 0
    Time Limit: 10000/5000 MS (Java/Others)
    Memory Limit: 65536/65536 K (Java/Others)
    Problem Description

    我们定义“区间的价值”为一段区间的最大值*最小值。

    一个区间左端点在L,右端点在R,那么该区间的长度为(R−L+1)

    现在聪明的杰西想要知道,对于长度为k的区间,最大价值的区间价值是多少。

    当然,由于这个问题过于简单。

    我们肯定得加强一下。

    我们想要知道的是,对于长度为1∼n的区间,最大价值的区间价值分别是多少。

    样例解释:

    长度为1的最优区间为22 答案为66

    长度为2的最优区间为45 答案为44

    长度为3的最优区间为24 答案为26

    长度为4的最优区间为25 答案为26

    长度为5的最优区间为15 答案为16

    Input
    多组测试数据
    第一行一个数n(1<=n<=100000)。
    第二行n个正整数(1<=ai<=10^9),下标从1开始。
    由于某种不可抗力,ai的值将会是1~10^9内随机的一个数。(除了样例)
    Output
    输出共n行,第i行表示区间长度为i的区间中最大的区间价值。
    Sample Input
    5
    1 6 2 4 4
    
    Sample Output
    36
    16
    12
    12
    6

    题解,构造两个线段树,分别求出最大与最小的坐标。然后利用用一个类似快排的方法,每次找到最大最小后,更新所有包含该区间的区间的值,然后选择最小的下标作为分割点,继续递归划分。为什么选最小坐标呢?
    我们假设当前区间为[l,r],该区间的最小值和最大值下标分别为min_p和max_p,那么[l,r]的答案由:
    1、左右端点都在[l,min_p)
    2、左右端点都在(min_p,r]
    3、左端点在[l,min_p)右端点在(min_p,r]
    4、N[min_p]*N[max_p](当前最小值和最大值的乘积)

    上诉四种情况中取最优
    我们发现3不可能比4更优,因为3的最小值一定会是N[min_p],最大值一定小于N[max_p],所以情况3可以剪去。所以直接递归处理1和2就可以。(可以想想为什么不能取max_p作为分割点)

    因为数据是随机的,所以这样递归处理的复杂度和快排类似,总的复杂度是nlognlogn//这里复杂度有点玄学,跑起来飞快。如有错误请指出



    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    #define lson l , m , rt << 1
    #define rson m + 1 , r , rt << 1 | 1
    const int maxn = 100010;
    int MAX[maxn<<2];
    int MIN[maxn<<2];
    long long ans[maxn];
    long long N[maxn];
    int Pos=0,n;
    long long read()
    {
        long long ans=0;
        char last=' ',ch=getchar();
        while(ch<'0' || ch>'9')last=ch,ch=getchar();
        while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
        if(last=='-')ans=-ans;
        return ans;
    }
    void PushUP_max(int rt)
    {
        if (N[MAX[rt<<1]] > N[MAX[rt<<1|1]])
            MAX[rt] = MAX[rt<<1] ;
        else
            MAX[rt] =MAX[rt<<1|1];
    }
    void PushUP_min(int rt)
    {
        if (N[MIN[rt<<1]] < N[MIN[rt<<1|1]])
            MIN[rt] = MIN[rt<<1] ;
        else
            MIN[rt] =MIN[rt<<1|1];
    }
    void build_max(int l,int r,int rt)
    {
        if (l == r)
        {
            MAX[rt]=++Pos;
            return ;
        }
        int m = (l + r) >> 1;
        build_max(lson);
        build_max(rson);
        PushUP_max(rt);
    }
    void build_min(int l,int r,int rt)
    {
        if (l == r)
        {
            MIN[rt]=MAX[rt];
            return ;
        }
        int m = (l + r) >> 1;
        build_min(lson);
        build_min(rson);
        PushUP_min(rt);
    }
    int query_max(int L,int R,int l,int r,int rt)
    {
        if (L <= l && r <= R)
        {
            return MAX[rt];
        }
        int m = (l + r) >> 1;
        int ret=0;
        N[0]=0;
        if (L <= m)
        {
            int tl=query_max(L , R , lson);
            if (N[tl]>N[ret])
                ret = tl;
        }
        if (R > m)
        {
            int tr=query_max(L , R , rson);
            if (N[tr]>N[ret])ret = tr;
        }
        return ret;
    }
    int query_min(int L,int R,int l,int r,int rt)
    {
        if (L <= l && r <= R)
        {
            return MIN[rt];
        }
        int m = (l + r) >> 1;
        int ret =0;
        N[0]=999999999;
        if (L <= m)
        {
            int tl=query_min(L , R , lson);
            if (N[tl]<N[ret])
                ret = tl;
        }
        if (R > m)
        {
            int tr=query_min(L , R , rson);
            if (N[tr]<N[ret])ret = tr;
        }
        return ret;
    }
    void sovle(int l,int r)
    {
        if (l>r) return ;
        int max_p=query_max(l , r , 1 , n , 1);
        int min_p=query_min(l , r , 1 , n , 1);
        long long num=N[max_p]*N[min_p];
        int nl,nr;
        if(max_p>min_p)
        {
            nl=min_p;
            nr=max_p;
        }
        else
        {
            nr=min_p;
            nl=max_p;
        }
        for (int i=nr-nl+1; i<=r-l+1; i++) ans[i]=max(ans[i],num);
        sovle(l,min_p-1);
        sovle(min_p+1,r);
    }
    int main()
    {
        while(~scanf("%d",&n))
        {
            getchar();
            memset(ans,0,sizeof(ans));
            for (int i=1; i<=n; i++)
                N[i]=read();
            Pos=0;
            build_max(1 , n , 1);
            build_min(1 , n , 1);
            sovle(1,n);
            for (int i=1; i<=n; i++)
                printf("%I64d
    ",ans[i]);
        }
        return 0;
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • 相关阅读:
    pongo英雄会-幸运数题解
    求最大公约数的算法
    第二课、GUI程序实例分析------------------狄泰软件学院
    第一课、GUI程序原理分析------------------狄泰软件学院
    第六十八课、拾遗:令人迷惑的写法
    第六十七课、经典问题解析五
    第六十六课、c++中的类型识别
    第六十五课、c++中的异常处理(下)
    第六十四课、c++中的异常处理(上)
    第六十三课、C语言的异常处理
  • 原文地址:https://www.cnblogs.com/scaugsh/p/5536681.html
Copyright © 2020-2023  润新知