Hdu4614 Vases and Flowers 二分+线段树

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4614

题目大意:
有n个空花瓶,编号 0~n-1,有两种操作,操作一,从A花瓶开始放F朵花,每个花瓶若没有花就放一朵,从A开始到n-1依次放,若没有花了或者遍历完花瓶了就不放了,要求输出第一朵被放的位置和最后一朵被放的位置,若没有花被放输出特定语句。操作二,清空A-B花瓶的花,输出被清理花的个数。

解题思路:
很简单的线段树区间更新,区间求和,但是要求对二分比较熟悉,一共要二分三次。
因为只要找到起始和终止的位置,所以依次找肯定超时,二分找就可以了。
找到第一朵花被放的位置,即第一个空的花瓶(左边界)

int askl(int a)//找到起始位置
{
    int l=a,r=n-1;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(mid-l+1>query(0,n-1,1,l,mid))
        r=mid;
        else
        l=mid+1;
    }
    return l;
}

若花未被放完找到最后一个放花的位置(右边界),这里mid=(l+r+1)>>1,否则会死循环,博主就卡在这了QAQ。

int askr(int a)//找到终止位置
{
    int l=a,r=n-1;
    while(l<r)
    {
        int mid=(l+r+1)>>1;
        if(r-mid+1>query(0,n-1,1,mid,r))
        l=mid;
        else
        r=mid-1;
    }
    return l;
}

若花被放完找到最后一个放花的位置。

int askrr(int a,int b)//放得完的终止位置
{
    int l=a,r=n-1;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(check(a,mid,b))
        r=mid;
        else
        l=mid+1;
    }
    return l;
}

其它就是正常的区间更新,区间求和,没什么好说的了。

完整AC代码

#include <iostream>
#include <stdio.h>
using namespace std;
const int maxn=5e4+5;
int tree[maxn<<2];
int lazy[maxn<<2];
int T,n,m;
void push_up(int k)
{
    tree[k]=tree[k<<1]+tree[k<<1|1];
}
void push_down(int l,int r,int k)
{
    if(lazy[k]==-1)
    return;
    int mid=(l+r)>>1;
    tree[k<<1]=lazy[k]*(mid-l+1);
    tree[k<<1|1]=lazy[k]*(r-mid);
    lazy[k<<1]=lazy[k<<1|1]=lazy[k];
    lazy[k]=-1;
}
void build(int l,int r,int k)
{
    lazy[k]=-1;
    if(l==r)
    {
        tree[k]=0;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
    push_up(k);
}
void update(int l,int r,int k,int ll,int rr,int w)
{
    if(ll<=l&&rr>=r)
    {
        tree[k]=(r-l+1)*w;
        lazy[k]=w;
        return;
    }
    push_down(l,r,k);
    int mid=(l+r)>>1;
    if(ll<=mid)
    update(l,mid,k<<1,ll,rr,w);
    if(rr>mid)
    update(mid+1,r,k<<1|1,ll,rr,w);
    push_up(k);
}
int query(int l,int r,int k,int ll,int rr)
{
    if(ll<=l&&rr>=r)
    {
        return tree[k];
    }
    push_down(l,r,k);
    int mid=(l+r)>>1;
    int ans=0;
    if(ll<=mid)
    ans+=query(l,mid,k<<1,ll,rr);
    if(rr>mid)
    ans+=query(mid+1,r,k<<1|1,ll,rr);
    return ans;
}
bool check(int l,int r,int k)
{
    int s=r-l+1-query(0,n-1,1,l,r);
    //cout<<"l "<<l<<" r "<<r<<" "<<query(0,n-1,1,l,r)<<endl;
    return s>=k;
}
int askl(int a)//找到起始位置
{
    int l=a,r=n-1;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(mid-l+1>query(0,n-1,1,l,mid))
        r=mid;
        else
        l=mid+1;
    }
    return l;
}
int askr(int a)//找到终止位置
{
    int l=a,r=n-1;
    while(l<r)
    {
        int mid=(l+r+1)>>1;
        if(r-mid+1>query(0,n-1,1,mid,r))
        l=mid;
        else
        r=mid-1;
    }
    return l;
}
int askrr(int a,int b)//放得完的终止位置
{
    int l=a,r=n-1;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(check(a,mid,b))
        r=mid;
        else
        l=mid+1;
    }
    return l;
}
int opt,a,b;
int first,last;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&m);
        build(0,n-1,1);
        while(m--)
        {
            scanf("%d",&opt);
            if(opt==1)
            {
                scanf("%d %d",&a,&b);
                int tag=n-a-query(0,n-1,1,a,n-1);
                //cout<<n-a<<" "<<query(0,n-1,1,a,n-1)<<endl;
                if(!tag)
                puts("Can not put any one.");
                else
                {
                    first=askl(a);
                    //cout<<"f "<<first<<endl;
                    if(tag==1)
                    {
                        last=first;
                        printf("%d %d\n",first,last);
                    }
                    else
                    {
                        if(tag>=b)//放得完
                        last=askrr(a,b);
                        else//放不完
                        last=askr(a);
                        printf("%d %d\n",first,last);
                    }
                    //cout<<"l "<<last<<endl;
                    update(0,n-1,1,first,last,1);
                }
            }
            else
            {
                scanf("%d %d",&a,&b);
                printf("%d\n",query(0,n-1,1,a,b));
                update(0,n-1,1,a,b,0);
            }
        }
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44491423/article/details/106026253