题意:一开始有标号为0~N-1的N个空花瓶,进行两种操作
操作1:A F,从标号为A的花瓶开始往后面放F朵花,如果当前花瓶有花了,就继续往后放,如果有花没有地方放了就丢掉。输出第一朵花和最后一朵花放的花瓶标号
操作2:A B,将花瓶A~B全部清空,并输出多少个花瓶被清空。
解法:
利用线段树的区间更新区间查询,线段树存储区间内有多少不为空的花瓶
对于操作1,先在[A,N-1]二分起点,再根据起点s二分[s,N-1]终点,要注意可能放不下所有的花的情况。
也可以在线段树上增加参数不用二分终点,会快很多。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 50005
int n,m;
int tree[maxn<<2],lazy[maxn<<2];
void down(int p,int la,int l,int r)
{
int mid=(l+r)>>1;
if (la==-1) return;
lazy[p<<1]=la;
lazy[p<<1|1]=la;
tree[p<<1]=la*(mid-l+1);
tree[p<<1|1]=la*(r-mid);
lazy[p]=-1;
}
void insert(int p,int L,int R,int l,int r,int flag)
{
if (l==L&&r==R)
{
tree[p]=flag*(R-L+1);
lazy[p]=flag;
return;
}
down(p,lazy[p],L,R);
int mid=(L+R)>>1;
if (r<=mid) insert(p<<1,L,mid,l,r,flag);
else if (l>mid) insert(p<<1|1,mid+1,R,l,r,flag);
else
{
insert(p<<1,L,mid,l,mid,flag);
insert(p<<1|1,mid+1,R,mid+1,r,flag);
}
tree[p]=tree[p<<1]+tree[p<<1|1];
}
int cal(int p,int L,int R,int l,int r)
{
if (l==L&&r==R) return tree[p];
down(p,lazy[p],L,R);
int mid=(L+R)>>1,res;
if (r<=mid) res=cal(p<<1,L,mid,l,r);
else if (l>mid) res=cal(p<<1|1,mid+1,R,l,r);
else res=cal(p<<1,L,mid,l,mid)+cal(p<<1|1,mid+1,R,mid+1,r);
tree[p]=tree[p<<1]+tree[p<<1|1];
return res;
}
int main()
{
int cas,d,a,b;
scanf("%d",&cas);
while (cas--)
{
scanf("%d%d",&n,&m);
memset(tree,0,sizeof(tree));
memset(lazy,-1,sizeof(lazy));
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&d,&a,&b);
if (d==1)
{
int l=a+1,r=n;
int s=-1,t=-1;
while (l<=r)
{
int mid=(l+r)>>1;
if (cal(1,1,n,a+1,mid)==mid-a) l=mid+1;
else r=mid-1,s=mid;
}
if (s==-1){printf("Can not put any one.\n");continue;}
l=s,r=n;
b=min(b,n-s+1-cal(1,1,n,s,n));
while (l<=r)
{
int mid=(l+r)>>1;
if (mid-s+1-cal(1,1,n,s,mid)>=b) t=mid,r=mid-1;
else l=mid+1;
}
printf("%d %d\n",s-1,t-1);
insert(1,1,n,s,t,1);
}
else
{
int tmp=cal(1,1,n,a+1,b+1);
insert(1,1,n,a+1,b+1,0);
printf("%d\n",tmp);
}
}
printf("\n");
}
return 0;
}