• BZOJ4239(线段树)


    一道权限题

    题面

    描述
    农夫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


    思想是比较奇妙的。

    仔细读题,我们发现草的高度成一个单调性(因为每株草每天的生长量是一定的),考虑把草sort排序,那么每次先找到第一个大于b的草,从它开始后面的草都要被割

    维护这样一些信息:

    day:从上一次收割到这一次过去的天数

    now:当前草的高度(每一次割草后那一串的草的高度都是b,那么对应区间now为b)

    ans:区间草高度和

    maxx:区间最高草的高度(对于每一次操作,如果最高草的高度都小于等于b,就可以不操作了)

    标记下传时,先传now,再传day(类比于赋值标记和加标记)。

    #include<bits/stdc++.h>
    #define LL long long
    #define N 500003
    using namespace std;
    LL read()
    {
        LL x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    LL a[N],sum[N];
    LL lc[N<<2],rc[N<<2],ans[N<<2],maxx[N<<2];
    LL day[N<<2],now[N<<2];
    LL ndnum=0;
    void pushup(LL k)
    {
        maxx[k]=max(maxx[lc[k]],maxx[rc[k]]);
        ans[k]=ans[lc[k]]+ans[rc[k]];
    }
    void build(LL k,LL l,LL r)
    {
        if(l==r){now[k]=-1;return;}
        LL mid=(l+r)>>1;
        build(lc[k]=++ndnum,l,mid);
        build(rc[k]=++ndnum,mid+1,r);
        pushup(k);
    }
    void push1(LL k,LL l,LL r,LL v)//now的下传 
    {
        now[k]=v;
        maxx[k]=v;
        ans[k]=(r-l+1)*v;//相当于直接覆盖 
        day[k]=0;//当前值变了,存的天数也就没什么用了 
    }
    void push2(LL k,LL l,LL r,LL v)//day的下传 
    {
        day[k]+=v;
        ans[k]+=(sum[r]-sum[l-1])*v;
        maxx[k]+=v*a[r]; 
    }
    void pushdown(LL k,LL l,LL r)
    {
        LL mid=(l+r)>>1;
        if(now[k]!=-1)
        {
            push1(lc[k],l,mid,now[k]);
            push1(rc[k],mid+1,r,now[k]);
            now[k]=-1;
        }
        if(day[k])
        {
            push2(lc[k],l,mid,day[k]);
            push2(rc[k],mid+1,r,day[k]);
            day[k]=0;
        }
    }
    void modify(LL k,LL L,LL R,LL l,LL r,LL v)
    {
        if(L>=l&&R<=r)
        {
            push1(k,L,R,v);
            return;
        }
        LL mid=(L+R)>>1;
        pushdown(k,L,R);
        if(l<=mid)modify(lc[k],L,mid,l,r,v);
        if(r>mid)modify(rc[k],mid+1,R,l,r,v);
        pushup(k);
    }
    LL query(LL k,LL l,LL r,LL v)
    {
        if(l==r)return l;
        LL mid=(l+r)>>1;
        pushdown(k,l,r);
        if(maxx[lc[k]]<=v)return query(rc[k],mid+1,r,v);
        else return query(lc[k],l,mid,v);
    }
    int main()
    {
        LL n=read(),m=read();
        build(1,1,n);
        for(int i=1;i<=n;++i)a[i]=read();
        sort(a+1,a+1+n);
        for(int i=1;i<=n;++i)
          sum[i]=a[i]+sum[i-1];
        LL d1=0;LL d2; 
        while(m--)
        {
            d2=read();LL b=read();
            day[1]+=d2-d1;maxx[1]+=(d2-d1)*a[n];ans[1]+=sum[n]*(d2-d1);
            d1=d2;
            if(maxx[1]<=b)
            {
                printf("0
    ");
                continue;
            }
            LL res=ans[1];
            LL pos=query(1,1,n,b);
            modify(1,1,n,pos,n,b);
            printf("%lld
    ",res-ans[1]);
        }
    } 
    View Code
  • 相关阅读:
    Chrome开发者工具中Elements(元素)断点的用途
    最简单的SAP云平台开发教程
    Java实现 LeetCode 495 提莫攻击
    Java实现 LeetCode 494 目标和
    Java实现 LeetCode 494 目标和
    Java实现 LeetCode 494 目标和
    Java实现 LeetCode 493 翻转对
    Java实现 LeetCode 493 翻转对
    Java实现 LeetCode 493 翻转对
    Java实现 LeetCode 492 构造矩形
  • 原文地址:https://www.cnblogs.com/yyys-/p/11324469.html
Copyright © 2020-2023  润新知