zoukankan      html  css  js  c++  java
  • BZOJ4293 Siano

    题头:

    描述
    农夫Byteasar买了一片n亩的土地,他要在这上面种草。 他在每一亩土地上都种植了一种独一无二的草,其中,第i亩土地的草每天会长高a[i]厘米。 Byteasar一共会进行m次收割,其中第i次收割在第d[i]天,并把所有高度大于等于b[i]的部分全部割去。Byteasar想知道,每次收割得到的草的高度总和是多少,你能帮帮他吗?
    Input
    第一行包含两个正整数n,m(1<=n,m<=500000),分别表示亩数和收割次数。 第二行包含n个正整数,其中第i个数为ai,依次表示每亩种植的草的生长能力。 接下来m行,每行包含两个正整数d[i],bi,依次描述每次收割。 数据保证d[1] < d[2] <… < d[m],并且任何时刻没有任何一亩草的高度超过10^12。
    Output
    输出m行,每行一个整数,依次回答每次收割能得到的草的高度总和。
    样例输入
    4 4
    1 2 4 3
    1 1
    2 2
    3 0
    4 4
    样例输出
    6
    6
    18
    0

    一道比较那啥的线段树题
    仔细读题
    我们需要两个标记
    一个mark进行区间加的操作(mark维护天数,实际增加的值是mark[ i ]*a[ i ])
    还需要一个marks进行区间更改为的操作
    然后对于每次输入
    mark增加的值为这一次输入的时间减上一次输入的时间
    然后我们维护两个值:区间和和区间最大值(两次区间和相减即使所求答案,区间最大值是方便进行区间更改为的操作,因为这样我们只需要下传标记到区间最大值大于b[ i ]的区间)
    维护区间和需要把区间a的值的和乘上mark,区间最大值加上天数乘区间a的最大值;
    我们只需要先从小到大排个序,保证单调性,这样找到最后一个高度小于b[ i ]的位置,我们就可以直接把从这儿往后都打上标记

    代码如下

    //siano
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    inline ll read(){
        char ch;
        while((ch=getchar())<'0'||ch>'9'){;}
        ll res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
        return res;
    } 
    long long a[500005],tre[2000007],mark[2000007],maxn[2000007],sum[500005],marks[2000007],d1;
    //tre:记录区间和,sum
    int n,m,l[2000007],r[2000007];
    inline ll max(ll a,ll b)
    {
        return a>b?a:b;
    }
    inline void buildtree(int p,int st,int end){
        l[p]=st,r[p]=end,mark[p]=0,marks[p]=-1;
    //marks初始化为-1,不能初始化为0(有可能是更改为0)
        if(st==end){tre[p]=maxn[p]=0;return;}
        int mid=(st+end)>>1;
        buildtree(p<<1,st,mid),buildtree((p<<1)+1,mid+1,end);
    }
    inline void pushup(int root)
    //向上传递
    {
        maxn[root]=max(maxn[(root<<1)],maxn[(root<<1)+1]);
        tre[root]=tre[(root<<1)]+tre[(root<<1)+1];
    }
    inline void pushnow(int root,ll v){
    //用mark更改区间
        mark[root]+=v;
        tre[root]+=v*(sum[r[root]]-sum[l[root]-1]);
        maxn[root]+=v*a[r[root]];
    }
    inline void pushnown(int root,ll k)
    //用marks更改区间
    {
        marks[root]=k;
        maxn[root]=k;
        tre[root]=k*(r[root]-l[root]+1);
        mark[root]=0;
    //因为更改区间以后前面的操作打下的mark,对当前答案不会有影响,所以把mark变为0;
    }
    inline void pushDown(int root)
    //向下传递
    {
        if(marks[root]!=-1)
        {
            pushnown((root<<1),marks[root]);
            pushnown((root<<1)+1,marks[root]);
            marks[root]=-1;
        }
        if(mark[root])
        {
            pushnow((root<<1),mark[root]);
            pushnow((root<<1)+1,mark[root]);
            mark[root]=0;
        }
    }
    inline void modify(int root,int ql,int qr,ll v){
    //更改区间值
        if(ql>r[root]||qr<l[root])return;
        if(ql<=l[root]&&r[root]<=qr){pushnown(root,v);return;}
        pushDown(root);
        int mid=(l[root]+r[root])>>1;
        if(qr<=mid)modify((root<<1),ql,qr,v);
        else if(ql>mid)modify((root<<1)+1,ql,qr,v);
        else modify((root<<1),ql,mid,v),modify((root<<1)+1,mid+1,qr,v);
        pushup(root);
    }
    inline ll query(int root,ll v){
    //查找第一个小于等于b[ i ]的位置    if(l[root]==r[root])return l[root];
        pushDown(root);
        if(maxn[(root<<1)]<=v)return query((root<<1)+1,v);
        return query((root<<1),v);
    }
    
    int  main(){
        n=read(),m=read();
        for(int  i=1;i<=n;i++)
        {
            a[i]=read();
        }
        sort(a+1,a+1+n);
        buildtree(1,1,n);
        for(int i=1;i<=n;i++)
        sum[i]=sum[i-1]+a[i];
        d1=0;
        for(int i=1;i<=m;i++)
        {
            ll d2=read(),b=read();
            maxn[1]+=(d2-d1)*a[n],tre[1]+=(d2-d1)*sum[n],mark[1]+=(d2-d1);
            if(maxn[1]<=b)
            {
                puts("0"),d1=d2;
                continue;
            }
            ll res=tre[1];
            int  pos=query(1,b);
            modify(1,pos,n,b);
            cout<<res-tre[1]<<'
    ',d1=d2;
        }
        return 0;
    }
  • 相关阅读:
    linux shell 的切换
    linux:TeamViewer安装使用详解
    虚拟机与主机互ping
    每R一点:层次聚类分析实例实战-dist、hclust、heatmap等(转)
    每R一点:各种画地图,全是知识点,90%人不知道!(转)
    R语言学习路线和常用数据挖掘包(转)
    SAS PROC MCMC example in R: Logistic Regression Random-Effects Model(转)
    SparkR安装部署及数据分析实例
    R语言的导数计算(转)
    awk之随机函数rand()和srand() (转)
  • 原文地址:https://www.cnblogs.com/forever-/p/9736095.html
Copyright © 2011-2022 走看看