jzoj 3191.【中山市选2013】花瓶 线段树

Description

小爱整天收到花。她有N个花瓶标号从0到N-1。如果她收到F朵花,她会选择一个花瓶A,尝试去放花进去那个花瓶。如果那个花瓶已经有花,她就顺序地找下一个,直到所有花都放完或者后面没有花瓶了。有时她会清理花瓶,把花瓶A到B(A<=B)之间的花全扔了。

Input

第一行两个整数N和M代表花瓶数和操作数。

然后M行每行第一个数字是K(1或2)。如果K是1,那么再输入A和F,如果K是2,那么输入A和B,含义如上所述。

Output

每个操作输出一行。

对于操作1,输出成功放花的第一个位置和最后一个位置,如果一朵花都没放,输出‘Can not put any one.’。

对于操作2,输出扔了多少花。

Sample Input

10 5

1 3 5

2 4 5

1 1 8

2 3 6

1 8 8

Sample Output

3 7

2

1 9

4

Can not put any one.

Data Constraint

对于40%的数据,有1≤N,M≤100。

对于100%的数据,有1≤N,M≤50000。

分析:用一个线段树维护一个区间的有花的花瓶数,对于询问随便搞搞就好。比较狗的是编号为0~N-1。

代码:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#define N 50001
#define inf 0x3f3f3f3f
#define fo(i,a,b) for (int i=a;i<=b;i++)

using namespace std;

int n,m,q,x,y,l,r,ans1,ans2,mid,g;
struct node{int x,q;};
node t[3*N];

void change(int p,int l,int r,int x,int y,int c)
{
    if ((l==x) && (r==y))
    {
        if (c==0) t[p].x=0,t[p].q=0;
             else t[p].x=r-l+1,t[p].q=1;
        return;    
    }
    if (t[p].q==c) return;
    int mid=(l+r)/2;
    if (t[p].q!=2) t[p*2].q=t[p*2+1].q=t[p].q;
    if (t[p].q==1) t[p*2].x=mid-l+1,t[p*2+1].x=r-mid;
    if (t[p].q==0) t[p*2].x=0,t[p*2+1].x=0;
    t[p].q=2;
    if (y<=mid) change(p*2,l,mid,x,y,c);
     else 
     {
        if (x>=mid+1) change(p*2+1,mid+1,r,x,y,c);
         else 
         {

            change(p*2,l,mid,x,mid,c);
            change(p*2+1,mid+1,r,mid+1,y,c);
         }
     }
     t[p].x=t[p*2].x+t[p*2+1].x;
}

int find(int p,int l,int r,int x,int y)
{
    if ((l==x) && (r==y))
    {
        return t[p].x;
    }
    if (t[p].q==1) 
    {
        return y-x+1;
    }
    if (t[p].q==0)
    {
        return 0;
    }
    int sum=0;
    int mid=(l+r)/2;
    if (y<=mid) sum+=find(p*2,l,mid,x,y);
     else 
     {
        if (x>=mid+1) sum+=find(p*2+1,mid+1,r,x,y);
         else 
         {
            sum+=find(p*2,l,mid,x,mid);
            sum+=find(p*2+1,mid+1,r,mid+1,y);
         }
     }
    return sum; 
}

int main()
{
    scanf("%d%d",&n,&m);
    fo(i,1,m)
    {
        scanf("%d%d%d",&q,&x,&y);
        if (q==1)
        {
            x++;
            l=x; r=n; ans1=inf;
            while (l<=r)
            {
                mid=(l+r)/2;
                g=mid-x+1;
                if (g-find(1,1,n,x,mid)!=0)
                {
                    r=mid-1;
                    ans1=min(ans1,mid);
                }
                else l=mid+1; 
            }
            l=x; r=n; ans2=inf;
            y=min(y,n-x+1-find(1,1,n,x,n));
            while (l<=r)
            {
                mid=(l+r)/2;
                g=mid-x+1;
                if (g-find(1,1,n,x,mid)>=y)
                {
                    r=mid-1;
                    ans2=min(ans2,mid);
                }
                else l=mid+1;
            }           
            if (find(1,1,n,x,ans2)==ans2-x+1)  printf("Can not put any one.\n");
                                          else printf("%d %d\n",ans1-1,ans2-1);                             
            change(1,1,n,x,ans2,1);
        }
        else
        {
            x++; y++;
            ans1=find(1,1,n,x,y);
            change(1,1,n,x,y,0);
            printf("%d\n",ans1);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值