题意:
有一排的空花瓶,编号从0至N-1,一个花瓶只能插入一朵花。
操作1是从x开始往后插入F朵花,如果碰到了插了花的花瓶则跳过,否则插花。
操作2是将x到y之间的花全部清空,问丢掉多少朵花。
思路:
用线段树存入区间的空花瓶的数量,因为从x到N之间的空花盆的数量是单调不下降的,所以可以用二分来做。
对于第一种操作,二分出插入第一朵和插入最后一朵花的位置,二分最后一朵花的位置,是用min(F,total)来二分。
对于第二种操作,直接查询就可以了。
代码:
#include
#include
#include
#include
using namespace std;
const int maxn=50005;
int tr[maxn<<2],lazy[maxn<<2];
int n,m,k,x,y;
void pushup(int i)
{
tr[i]=tr[i*2]+tr[i*2+1];
}
void pushdown(int i,int len)
{
if(lazy[i]!=-1)
{
lazy[i*2]=lazy[i*2+1]=lazy[i];
tr[i*2]=(len-len/2)*lazy[i];
tr[i*2+1]=len/2*lazy[i];
lazy[i]=-1;
}
return;
}
void build(int i,int l,int r)
{
lazy[i]=-1;
if(l==r)
{
tr[i]=1;
return;
}
int mid=(l+r)/2;
build(2*i,l,mid);
build(2*i+1,mid+1,r);
pushup(i);
return;
}
void update(int i,int l,int r,int x,int y,int c)
{
if(x<=l&&r<=y)
{
tr[i]=(r-l+1)*c;
lazy[i]=c;
return;
}
pushdown(i,r-l+1);
int mid=(l+r)/2;
if(x<=mid) update(2*i,l,mid,x,y,c);
if(y>mid) update(2*i+1,mid+1,r,x,y,c);
pushup(i);
return;
}
int query(int i,int l,int r,int x,int y)
{
int sum=0;
if(x<=l&&r<=y)
{
return tr[i];
}
pushdown(i,r-l+1);
int mid=(l+r)/2;
if(x<=mid) sum+=query(2*i,l,mid,x,y);
if(y>mid) sum+=query(2*i+1,mid+1,r,x,y);
pushup(i);
return sum;
}
int findpos(int x,int num)//二分位置
{
int l=x,r=n;
int pos,mid;
while(l<=r)
{
mid=(l+r)/2;
if(query(1,1,n,x,mid)>=num)
pos=mid,r=mid-1;
else
l=mid+1;
}
return pos;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
build(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&k,&x,&y);
if(k==1)
{
x++;
int total=query(1,1,n,x,n);
if(total==0)
printf("Can not put any one.\n");
else
{
int pos1=findpos(x,1);
int pos2=findpos(x,min(y,total));
printf("%d %d\n",pos1-1,pos2-1);
update(1,1,n,pos1,pos2,0);
}
}
else
{
x++,y++;
printf("%d\n",y-x+1-query(1,1,n,x,y));
update(1,1,n,x,y,1);
}
}
printf("\n");
}
return 0;
}