• Siano


    Siano (线段树 (starstar))

    • 农夫 (Byteasar) 买了一片 (n) 亩的土地,他要在这上面种草。
    • 他在每一亩土地上都种植了一种独一无二的草,其中,第 (i) 亩土地的草每天会长高 (a_i) 厘米。
    • (Byteasar) 一共会进行 (m) 次收割,其中第 (i) 次收割在第 (d_i) 天,并把所有高度大于等于 (b_i) 的部分全部割去。
    • (Byteasar) 想知道,每次收割得到的草的高度总和是多少,你能帮帮他吗?

    Input

    • 第一行包含两个正整数 (n,m) , 分别表示亩数和收割次数。
    • 第二行包含 (n) 个正整数,其中第 (i) 个数为 (a_i),依次表示每亩种植的草的生长能力。
    • 接下来 (m) 行,每行包含两个正整数 (d_i,b_i) ,依次描述每次收割。

    Output

    • 输出 (m) 行,每行一个整数,依次回答每次收割能得到的草的高度总和。

    Sample Input

    4 4
    1 2 4 3
    1 1
    2 2
    3 0
    4 4
    

    Sample Output

    6
    6
    18
    0
    

    Hint

    • 样例解释
      • (1) 天,草的高度分别为(1,2,4,3),收割后变为(1,1,1,1)
      • (2) 天,草的高度分别为 (2,3,5,4),收割后变为 (2,2,2,2)
      • (3) 天,草的高度分别为 (3,4,6,5),收割后变为 (0,0,0,0)
      • (4) 天,草的高度分别为 (1,2,4,3) ,收割后变为 (1,2,4,3)
    • 对于$ 100%$ 的数据,(1le n,mle 5 imes 10^5 ,1le a_ile 10^6,1le d_i,b_ile 10^{12})
    • 数据保证 (d_1<d_2<...<d_m),并且任何时刻没有任何一亩草的高度超过 (10^{12})
    • 来源:(bzoj4293)

    分析

    • 这个题嘛……大家的题解都说线段树,时限也开了30s明摆着告诉你是nlogn……

      不过我们发现a[i]<=10^6

      那么我就有一个以空间换时间的做法,并且只需要用很小的空间就可以把复杂度降到O(n)(或者说是O(maxa[i]+n))

      首先,这个被收割的稻草的A值显然有单调性,换句话说,每次收割都会有一个左端点

      接着,我们发现,如果初始高度确定,生长时间确定,收割的门槛也确定,那么被收割的最低高度是可以算出来的

      那么我们可以搞个单调栈,然后搞一搞就做完了

    Code

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #define ll long long
    #define N 1000006
     
    using namespace std;
    inline ll read(){
        ll ret=0;char ch=getchar();
        while (ch<'0'||ch>'9') ch=getchar();
        while ('0'<=ch&&ch<='9'){
            ret=ret*10-48+ch;
            ch=getchar();
        }
        return ret;
    }
    int n;
    ll a[N],s[N];
    ll d[N/2],b[N/2],day;
    int stk[N/2],top;
    int to[N/2];
    const int m=1e6;
     
    int main(){
        n=read();day=read();
        for (int i=1;i<=n;++i) ++a[read()];
        for (int i=1;i<=day;b[i++]=read()) d[i]=read();
        s[0]=a[0]=0;
        for (int i=1;i<=m;++i) s[i]=s[i-1]+(ll)a[i]*i;
        for (int i=1;i<=m;++i) a[i]+=a[i-1];
        to[0]=d[0]=b[0]=0;
        top=0;stk[top++]=0;
        for (int k=1;k<=day;++k){
            ll res=0;
            int last=m,x=max((ll)to[stk[top-1]],min((b[k]-b[stk[top-1]])/(d[k]-d[stk[top-1]]),(ll)m));
            for (;x<last;x=max((ll)to[stk[top-1]],min((b[k]-b[stk[top-1]])/(d[k]-d[stk[top-1]]),(ll)m))){
                res+=(d[k]-d[stk[top-1]])*(s[last]-s[x])+(b[stk[top-1]]-b[k])*(a[last]-a[x]);
                if ((last=x)>to[stk[top-1]]) break;
                if (!--top) break;
            }
            if ((to[k]=last)<m) stk[top++]=k;
            printf("%lld
    ",res);
        }
        return 0;
    }
    
  • 相关阅读:
    【WPF】 打开本地的文件或者文件夹
    Angularjs中的拦截器 (卧槽,好牛逼)
    oracle中to_date() 与 to_char() 日期和字符串转换
    mysql中如何嵌套使用insert和select
    angularjs中的路由介绍详解 ui-route
    sql中的or的用法说明
    AngularJS路由 $state服务、路由事件、获取路由参数
    No identifier specified for entity
    常用正则表达式集锦
    APP_Store
  • 原文地址:https://www.cnblogs.com/hbhszxyb/p/13223731.html
Copyright © 2020-2023  润新知