zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    mac安装numpy引发的一系列问题
    HttpWebRequest提交数据
    Codeigniter Setting 增强配置类
    WPF 创建无边框的圆角窗口
    wpf textbox只能输入数字,屏蔽中文输入
    Frame用navigate导航到新页面后导航条隐藏的方法
    WPF利用VisualTreeHelper遍历寻找对象的子级对象或者父级对象
    GitHub for Visual Studio使用讲解
    mvvmlight下passwordBox绑定的解决方法
    WPF+MVVM+EF示例1
  • 原文地址:https://www.cnblogs.com/yyys-/p/11324469.html
Copyright © 2011-2022 走看看