题目
有n(1<=n<=5e4)个花瓶,标号为0到n-1
有m(1<=m<=5e4)次操作,操作分为两种
①从A花瓶起,向右插入B枝花,
即从A向右遍历,有空的花瓶就插进去,
如果到n-1号花瓶还没插满就丢弃剩下的花,
输出最后的最左和最右的插入花的位置,如果一朵花也插不下输出Can not put any one.
②将[A,B]区间的花瓶清空,
输出清空的花的数量
思路来源
https://blog.csdn.net/blessLZH0108/article/details/74931021
题解
区间赋值+区间求和,用1表示空花瓶,0表示满花瓶
对于一操作,
最左边的位置,二分[A,l]的第一个空花瓶的位置l
最右边的位置r分两种情况,
①[A,n-1]能放下B枝花,二分[l,r]的第一个能放满B枝花的位置
②[A,n-1]放不下B枝花,那么只需要把[A,n-1]放满,
要么求出[A,n-1]的花数num之后,二分[l,r]的第一个能放满num枝花的位置
要么从右向左二分,二分出[r,n-1]的第一个空花瓶的位置
然后对于[l,r]区间赋0即可
对于二操作,
每次统计区间内空花瓶的数量,用区间长减去即可
代码
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=5e4+10;
int t,n,m;
int op,x,y,l,r;
int L,R;//二分上下界
int dat[maxn*5],cov[maxn*5];
void pushup(int p)
{
dat[p]=dat[p<<1]+dat[p<<1|1];
}
void build(int p,int l,int r)
{
dat[p]=r-l+1;
cov[p]=-1;
if(l==r)return;
int mid=(l+r)/2;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void pushdown(int p,int l,int r)
{
if(~cov[p])
{
int mid=(l+r)/2;
dat[p<<1]=cov[p]?(mid-l+1):0;
dat[p<<1|1]=cov[p]?(r-mid):0;
cov[p<<1]=cov[p];
cov[p<<1|1]=cov[p];
cov[p]=-1;
}
}
void update(int p,int l,int r,int ql,int qr,int op)
{
if(ql<=l&&r<=qr)
{
dat[p]=op?(r-l+1):0;
cov[p]=op;
return;
}
pushdown(p,l,r);
int mid=(l+r)/2;
if(ql<=mid)update(p<<1,l,mid,ql,qr,op);
if(qr>mid)update(p<<1|1,mid+1,r,ql,qr,op);
pushup(p);
}
int ask(int p,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)return dat[p];
pushdown(p,l,r);
int ans=0,mid=(l+r)/2;
if(ql<=mid)ans+=ask(p<<1,l,mid,ql,qr);
if(qr>mid)ans+=ask(p<<1|1,mid+1,r,ql,qr);
return ans;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
build(1,0,n-1);
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&op,&x,&y);
if(op==2)
{
printf("%d\n",(y-x+1)-ask(1,0,n-1,x,y));
update(1,0,n-1,x,y,1);
}
else
{
l=r=-1;
L=x;R=n-1;
while(L<=R)
{
int mid=(L+R)/2;
//printf("mid:%d\n",mid);
//printf("v:%d\n",ask(1,0,n-1,x,mid));
if(ask(1,0,n-1,x,mid)>=1)l=mid,R=mid-1;//往左缩
else L=mid+1;
}
if(l==-1)
{
puts("Can not put any one.");
continue;
}
L=x;R=n-1;
if(ask(1,0,n-1,l,n-1)<y)
{
while(L<=R)
{
int mid=(L+R)/2;
if(ask(1,0,n-1,mid,n-1)>=1)r=mid,L=mid+1;//往右扩
else R=mid-1;
}
}
else
{
while(L<=R)
{
int mid=(L+R)/2;
if(ask(1,0,n-1,x,mid)>=y)r=mid,R=mid-1;//往左缩
else L=mid+1;
}
}
update(1,0,n-1,l,r,0);
printf("%d %d\n",l,r);
}
}
puts("");
}
return 0;
}