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 
#include 
#include 
#include 
#include 
#include 
#include 
#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


你可能感兴趣的:(线段树)