Processing math: 100%

Siano

Siano (线段树 )

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

Input

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

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 的数据,1n,m5×1051ai1061di,bi1012
  • 数据保证 d1<d2<...<dm,并且任何时刻没有任何一亩草的高度超过 1012
  • 来源: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\n",res);
    }
    return 0;
}
posted @   ♞老姚♘  阅读(250)  评论(0编辑  收藏  举报
编辑推荐:
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
阅读排行:
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· PPT革命!DeepSeek+Kimi=N小时工作5分钟完成?
· What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
· 赶AI大潮:在VSCode中使用DeepSeek及近百种模型的极简方法
· DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地
点击右上角即可分享
微信分享提示