• 线段树 乌鸦喝水


    问题 B: 乌鸦喝水
    时间限制: 2 Sec 内存限制: 128 MB
    题目描述
    【题目背景】
    一只乌鸦在自娱自乐,它在面前放了n个有魔力的水缸,水缸里装有无限的水。
    【题目描述】
    他准备从第1个水缸飞到第n个水缸,共m次。在飞过一个水缸的过程中,如果他能够得着水缸里的水,即水缸口到水面距离小于等于乌鸦能够得着的深度,那它就会喝水缸里的水。每喝一次水,所有水缸里的水位都会下降,第i个水缸里的水位会下降Ai,注意喝水是瞬间的,如果乌鸦刚好够得着,但喝完之后够不着,也视为喝到一次,水位也会相应的下降。
    Input
    共有3行。第一行有三个正整数n、m和x,用空格隔开。n表示水缸的数量,m表示乌鸦飞的次数,x表示乌鸦能够得着的深度。第二行,有n个用空格隔开的正整数,第i个数为第i个水缸中水缸口到水面的距离Wi。第三行,有n个用空格隔开的正整数,第i个为Ai。
    Output
    只有一行,这一行只有一个正整数,为这只乌鸦能喝到水的次数。
    Sample Input
    5 2 20
    15 14 13 12 12
    1 1 1 1 1
    Sample Output
    9
    【数据范围】
    100%的数据,0<n≤100000,0<m≤100000,0<x≤2000000000,0<Wi≤2000000000,0<Ai≤200。

    设 num=(X-w[i])/a[i]这个就是当前的缸还能撑住水位下降几次。
    又因为虽然他能撑住这么多次,但是乌鸦飞到他上面前还要过i-1个缸,又要喝水。
    所以num[i]=(X-w[i])/a[i]-i+1;这样就可以了。但是如果前面的一个缸不会被喝水,那么后面就被多减了,其实可以找到第一个会被干掉的点,删掉,再给他后面的区间+1,就又解决了。耳罩第一个不符合的点只要维护个区间最小,二分一下。
    所以每一轮只要删掉所有不满足的,给后面加回来,让ans+=根节点上符合的个数就好了。
    跑得贼快。

    #pragma GCC optimize("O3")
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define N 100005
    #define mod 10000000007ll
    #define ll long long
    using namespace std;
    struct tree{int l,r;ll h,lz,sum;}t[N*4];
    int n,m;ll ans,X,w[N],a[N],zz[N];
    ll min(ll x,ll y){return x<y?x:y;}
    void down(int x)
    {
        ll l=t[x].lz;t[x].lz=0;
        t[x*2].h+=l;t[x*2].lz+=l;
        t[x*2+1].h+=l;t[x*2+1].lz+=l;
    }
    void build(int l,int r,int x)
    {
        t[x].l=l;t[x].r=r;
        if(l==r)
        {
            t[x].h=(X-w[l])/a[l]-l+1;
            t[x].sum=1;
            return;
        }
        int mid=l+r>>1;
        build(l,mid,x*2);build(mid+1,r,x*2+1);
        t[x].sum=t[x*2].sum+t[x*2+1].sum;
        t[x].h=min(t[x*2].h,t[x*2+1].h);
    }
    void c(int l,int r,int x)
    {
        if(l>r)return ;
        if(t[x].l>=l&&t[x].r<=r)
        {
            t[x].h++;t[x].lz++;
            return;
        }
        if(t[x].lz)down(x);
        int mid=t[x].l+t[x].r>>1;
        if(l<=mid)c(l,r,x*2);
        if(r>mid)c(l,r,x*2+1);
        t[x].sum=t[x*2].sum+t[x*2+1].sum;
        t[x].h=min(t[x*2].h,t[x*2+1].h);
    }
    void del(int l,int x)
    {
        if(t[x].l==t[x].r)
        {
            t[x].h=mod;t[x].sum=0;
            return;
        }
        int mid=t[x].l+t[x].r>>1;
        if(t[x].lz)down(x);
        if(l<=mid)del(l,x*2);
        else del(l,x*2+1);
        t[x].sum=t[x*2].sum+t[x*2+1].sum;
        t[x].h=min(t[x*2].h,t[x*2+1].h);
    }
    int q(ll k,int x)
    {
        if(t[x].l==t[x].r)return t[x].l;
        if(t[x].lz)down(x);
        if(t[x*2].h<k)return q(k,x*2);
        else return q(k,x*2+1);
    }
    int main()
    {
        //freopen("hh.txt","r",stdin);
    //  freopen(".out","w",stdout);
        scanf("%d%d%lld",&n,&m,&X);
        for(int i=1;i<=n;i++)scanf("%lld",&w[i]);
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
        build(1,n,1);
        while(m--)
        {
            while(t[1].h<ans)
            {
                //cout<<t[1].h<<endl;
                int k=q(ans,1);
                del(k,1);c(k+1,n,1);
            }
            ans+=t[1].sum;
            if(!t[1].sum)break;
        }
        printf("%lld
    ",ans);
    }
  • 相关阅读:
    夏天里的敏捷:10月底总结会议笔记【问题笔记】
    如何给项目里面每个功能点设权限?
    操作svn汉化
    夏天里的敏捷[1]:搬家记
    如何去读一个有50万行代码的项目?
    如何去定位你在调用哪个function()?
    小鸡和代码代码重构[2]:MOVE METHOD
    SVN版本管理随笔
    .NET服务器端控件绑定数据源的问题
    看视频笔记1【wpf】
  • 原文地址:https://www.cnblogs.com/QTY2001/p/7674425.html
Copyright © 2020-2023  润新知