hdu 4614 Vases and Flowers (二分 线段树)

题目大意:爱丽丝有N个花瓶,每个花瓶最多放一朵花。然后又如下两个操作。

1:A B    从第A个花瓶开始,往后依次插B朵花,直到不能插为止。如果一朵花都不能插入就输出“can.....”,否则输出第一个插花位置和最后一个插花位置。

2:A B    输出A B 之间有多少朵花   然后将这些花瓶清空。


当时比赛的时候始终找不到办法求出 最后一个插花位置。  也想过二分  但是想着怕效率太慢就没写。

其实最后想想也是 只有50000个操作   再乘以log N的二分  最多也就20W左右吧。   


我是弱菜,自己写的程序效率巨慢。而且数组也开得多。


思路:

用lef 记录每个区间最左边可以放的花瓶,如果没有就是INF  

用rig 记录每个区间最右边可以放的花瓶,如果没有就是-1

以上两个在更新的时候  lef选较小的   rig选较大的

cov表示区间全空 0 还是全满1  ,或者是不空不满  -1

然后emp表示区间空花瓶数。

主要的难点就是可以插花的时候怎么找到最后一个插花位置。

那么就用二分  找那个 emp ==  所需要插花的数量 的最小右边的区间。

详见代码。


 

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <cmath>

#include <vector>

#include <map>

#include <set>

#define maxn 50005

#define lson num<<1,s,mid

#define rson num<<1|1,mid+1,e

#define INF 0x3f3f3f3f

using namespace std;



int emp[maxn<<2];

int cov[maxn<<2];

int lef[maxn<<2];

int lzy[maxn<<2];

int rig[maxn<<2];



void pushup(int num)

{

    emp[num]=emp[num<<1]+emp[num<<1|1];



    if(cov[num<<1]==0 && cov[num<<1|1]==0)cov[num]==0;

    else if(cov[num<<1|1]==1 && cov[num<<1]==1)cov[num]=1;

    else cov[num]=-1;

    lef[num]=min(lef[num<<1],lef[num<<1|1]);

    rig[num]=max(rig[num<<1|1],rig[num<<1]);

}



void pushdown(int num,int s,int e)

{

    if(lzy[num]!=0)

    {

        int mid=(s+e)>>1;



        lzy[num<<1]=lzy[num<<1|1]=lzy[num];



        if(cov[num]!=-1)cov[num<<1]=cov[num<<1|1]=cov[num];



        if(cov[num<<1]==0)emp[num<<1]=mid-s+1;

        else if(cov[num<<1]==1)emp[num<<1]=0;



        if(cov[num<<1|1]==0)emp[num<<1|1]=e-mid;

        else if(cov[num<<1|1]==1)emp[num<<1|1]=0;



        if(cov[num]==0)

        {

            lef[num<<1]=s;

            rig[num<<1]=mid;

            lef[num<<1|1]=mid+1;

            rig[num<<1|1]=e;

        }

        else

        {

            lef[num<<1]=lef[num<<1|1]=INF;

            rig[num<<1]=rig[num<<1|1]=-1;

        }

        lzy[num]=0;

    }

}



void build(int num,int s,int e)

{

    cov[num]=0;

    lef[num]=s;

    rig[num]=e;

    emp[num]=e-s+1;

    lzy[num]=0;

    if(s==e)return;

    int mid=(s+e)>>1;



    build(lson);

    build(rson);

    pushup(num);

}



void update(int num,int s,int e,int l,int r,int val)

{

    if(l<=s && r>=e)

    {

        lzy[num]=1;

        cov[num]=val;

        emp[num]=val==0?e-s+1:0;

        lef[num]=val==0?s:INF;

        rig[num]=val==0?e:-1;

        return;

    }

    pushdown(num,s,e);

    int mid=(s+e)>>1;

    if(l<=mid)update(lson,l,r,val);

    if(r>mid)update(rson,l,r,val);

    pushup(num);

}



int query(int num,int s,int e,int l,int r)

{

    //printf("emp=%d,s=%d,e=%d,l=%d,r=%d,cov=%d\n",emp[num],s,e,l,r,cov[num]);

    if(l<=s && r>=e)

    {

        return emp[num];

    }

    pushdown(num,s,e);

    int mid=(s+e)>>1;

    if(r<=mid)return query(lson,l,r);

    else if(l>mid)return query(rson,l,r);

    else return query(lson,l,mid)+query(rson,mid+1,r);

    pushup(num);

}



int Q_L(int num,int s,int e,int l,int r)//找到区间的LEF 

{

    if(l==s && r==e)

    {

        return lef[num];

    }



    pushdown(num,s,e);

    int mid=(s+e)>>1;

    if(r<=mid)return Q_L(lson,l,r);

    else if(l>mid)return Q_L(rson,l,r);

    else return min(Q_L(lson,l,mid),Q_L(rson,mid+1,r));

    pushup(num);

}



int main()

{

    int T;

    scanf("%d",&T);

    while(T--)

    {

        int n,m;

        scanf("%d%d",&n,&m);



        build(1,1,n);//额额额。  我是用1-N 建的树  而题目说的是 0-N-1  所以。。。后面有一些++操作。。。

        int tl,tr;

        while(m--)

        {

            int op,aa,bb;

            scanf("%d%d%d",&op,&aa,&bb);



            if(op==1)

            {

                aa++;

                int ll=Q_L(1,1,n,aa,n);//找到左边

                if(ll==INF)

                {

                    printf("Can not put any one.\n");

                    continue;

                }

                printf("%d ",ll-1);

                int ttmp=query(1,1,n,ll,n);



                if(ttmp==0)

                printf("Can not put any one.\n");

                else

                {

                    if(ttmp<=bb)

                    {

                        printf("%d\n",rig[1]-1);

                        update(1,1,n,ll,n,1);

                    }

                    else

                    {

                        int top=n,bot=ll,mid;

                        while(bot<=top)

                        {

                            mid=(bot+top)>>1;

                            int bin=query(1,1,n,ll,mid);

                            if(bin>bb)

                            top=mid-1;

                            else if(bin<bb)

                            bot=mid+1;

                            else break;

                        }

                        while(query(1,1,n,ll,mid)==bb)//找到最小的

                        {

                            mid--;

                            if(mid<=ll)break;

                        }

                        printf("%d\n",mid+1-1);

                        update(1,1,n,ll,mid+1,1);

                    }

                }

            }

            else

            {

                aa++,bb++;

                printf("%d\n",bb-aa+1-query(1,1,n,aa,bb));

                update(1,1,n,aa,bb,0);

            }

        }

        puts("");

    }

    return 0;

}


 

 

你可能感兴趣的:(HDU)