L - Vases and Flowers(线段树+二分查找)

  Alice is so popular that she can receive many flowers everyday. She has N vases numbered from 0 to N-1. When she receive some flowers, she will try to put them in the vases, one flower in one vase. She randomly choose the vase A and try to put a flower in the vase. If the there is no flower in the vase, she will put a flower in it, otherwise she skip this vase. And then she will try put in the vase A+1, A+2, ..., N-1, until there is no flower left or she has tried the vase N-1. The left flowers will be discarded. Of course, sometimes she will clean the vases. Because there are too many vases, she randomly choose to clean the vases numbered from A to B(A <= B). The flowers in the cleaned vases will be discarded.

Input

  The first line contains an integer T, indicating the number of test cases.
  For each test case, the first line contains two integers N(1 < N < 50001) and M(1 < M < 50001). N is the number of vases, and M is the operations of Alice. Each of the next M lines contains three integers. The first integer of one line is K(1 or 2). If K is 1, then two integers A and F follow. It means Alice receive F flowers and try to put a flower in the vase A first. If K is 2, then two integers A and B follow. It means the owner would like to clean the vases numbered from A to B(A <= B).

Output

  For each operation of which K is 1, output the position of the vase in which Alice put the first flower and last one, separated by a blank. If she can not put any one, then output 'Can not put any one.'. For each operation of which K is 2, output the number of discarded flowers.
   Output one blank line after each test case.

Sample Input

2
10 5
1 3 5
2 4 5
1 1 8
2 3 6
1 8 8
10 6
1 2 5
2 3 4
1 0 8
2 2 5
1 4 4
1 2 3

Sample Output

[pre]3 7
2
1 9
4
Can not put any one.

2 6
2
0 9
4
4 5
2 3

[/pre]

题解:我们可用用线段树记录每个节点的性质,为1即代表该位置可放花,为0代表该位置已经有花了,不能放了。

其实也可以反着来,稍稍更改一下代码即可。记得要打上lazy哦。还有注意下标的统一性和二分查找的范围~~

#include<iostream>
#include<stdio.h>
using namespace std;
const int maxn=50050;
int n,m,k,x,y;
int sum[maxn<<2],lazy[maxn<<2];//sum记录该节点是否为空花瓶,1代表为可插的空花瓶,0代表该花瓶里已有花(其实这里可以反着来,简单修改下其他地方的代码即可)
void pushup(int rt) //往上更新
{
    sum[rt]=sum[rt*2]+sum[rt*2+1];
}
void pushdown(int l,int r,int rt)//下放
{
    if(lazy[rt]!=-1)
    {
        int mid=(l+r)/2;
        lazy[rt*2]=lazy[rt*2+1]=lazy[rt];//左右下放lazy
        sum[rt*2]=(mid-l+1)*lazy[rt];//左边更新(长度为mid-l+1,分奇偶两种试验一下即可明白)
        sum[rt*2+1]=(r-mid)*lazy[rt];//右边更新(长度为r-mid,同理)
        lazy[rt]=-1;//取消标记
    }
}

void build(int l,int r,int rt)//建树
{
    sum[rt]=1;
    lazy[rt]=-1;
    if(l==r)
    {
        return ;
    }
    int mid=(l+r)/2;
    build(l,mid,rt*2);
    build(mid+1,r,rt*2+1);
    pushup(rt);//注意往上更新
}
void update(int L,int R,int l,int r,int x,int rt)//将L到R区间的值更改为x
{
    if(L<=l&&R>=r)
    {
        sum[rt]=(r-l+1)*x;//加上整个区间的值
        lazy[rt]=x;//打上lazy
        return ;
    }
    pushdown(l,r,rt);//下放
    int mid=(l+r)/2;
    if(L<=mid)  //左右更新就不再赘述了
        update(L,R,l,mid,x,rt*2);
    if(R>=mid+1)
        update(L,R,mid+1,r,x,rt*2+1);
    pushup(rt);
}
int querysum(int L,int R,int l,int r,int rt)//查询L到R区间中可用花瓶的个数
{
    if(L<=l&&R>=r)
        return sum[rt];
    pushdown(l,r,rt);
    int mid=(l+r)/2;
    int ans=0;
    if(L<=mid)
        ans+=querysum(L,R,l,mid,rt*2);
    if(R>=mid+1)
        ans+=querysum(L,R,mid+1,r,rt*2+1);
    return ans;
}
int Binary_search(int s,int num)//从s起二分查找可用花瓶个数为num的下标
{
    int ans=0;
    int l=s,r=n;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(querysum(s,mid,1,n,1)>=num)//注意这里是从初始左值s到mid查找值,不是l!!!
            ans=mid,r=mid-1;
        else
            l=mid+1;
    }
    return ans;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        build(1,n,1);
        for(int i=1;i<=m;i++)
        {
            cin>>k>>x>>y;
            if(k==1)
            {
                x++;//x加1是为了下标的统一性,为下面输出L-1,R-1做了准备
                int r=querysum(x,n,1,n,1);
                if(r==0)//如果从x起所有花瓶都有花了,就一个也不能放了,其他的就算只有一个也可以
                    puts("Can not put any one.");
                else
                {
                    int L=Binary_search(x,1);//从s起查找第一个可以放花的位置,即左值
                    int R=Binary_search(x,min(y,r));//从s起查找最后一个可以放花的位置,即右值
                    cout<<L-1<<" "<<R-1<<endl;//和题目要求的下标相统一
                    update(L,R,1,n,0,1);//注意别忘了更新,要将你所有放的花将sum数组置为0,表示该位置不可放花了
                }
            }
            else
            {
                x++;//为下标相统一
                y++;
                cout<<y-x+1-querysum(x,y,1,n,1)<<endl;//区间长度减去空瓶子(可以放花即为空瓶子,这是由你自己设置的功能决定的)的个数即为全部的花数
                update(x,y,1,n,1,1);//注意别忘了更新
            }

        }
        cout<<endl;//注意别忘了空格,会PE的~~
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43824158/article/details/88651736