题目链接
http://acm.hdu.edu.cn/showproblem.php?pid=4614
题意:
有n个花瓶,标号0 ~ n−1。m个操作,
1AF,表示从A位置开始插FF朵花,遇到有花的花瓶跳过。到最后一个花瓶都还有花剩余,丢弃剩下的花。
2AB,表示将区间[A,B]内的花瓶全部清空。(A≤B)(A≤B)
对于每个11操作,输出第一个和最后一个插花的位置,如果一朵花都插不了,输出‘Can not put any one.’;对于每个2操作,输出区间[A,B]内被清空的花瓶的数量。
思路:
我们这里建树的时候,标号为(1 - n)但是题目给出的标号为0 - n -1
而且我们标记为插花为1,插花后为0
对于操作2,就是求区间和,然后用r - l + 1 - 区间和就可以了
对于操作1,我第一时间想的就是递归到树的底层进行操作,但是这样应该时间会挺长的,可以先把 起点 ->n中间空花瓶数量求出来,如果 == 0就输出Can not put any one.
如果不为0,
就二分查找从起点开始能恰好将第一朵花插入的位置,以及最后一朵花插入的位置,也即是找到一个区间,其空间,恰好可以将满足要插入花的数量,最后更新一下区间内空花瓶 减少的数量
/*1代表该花瓶为空,0表示该花瓶已经插花*/
#include
#include
#include
using namespace std;
const int N=5e4+10;
int sum[N*4],lazy[4*N];
//lazy[rt] == 0表示这个区间全被插满花,1为全空
void PushUp(int rt)
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void Pushdown(int rt,int ln,int rn)
{
if(lazy[rt] != -1){
//因为要修改满足条件的区间,这个区间不全为1就是全为0
//所以只需要记录这个满足条件的区间被清成0或者1即可
lazy[rt<<1] = lazy[rt];
lazy[rt<<1|1] = lazy[rt];
sum[rt<<1] = ln * lazy[rt];
sum[rt<<1|1] = rn * lazy[rt];
lazy[rt] = -1;
}
}
void Update(int ql,int qr,int val,int l,int r,int rt)
{
if(ql <= l&&r <= qr){
/*这里lazy直接赋值标记在于:
1、如果是插花,这个区间一等是恰好能够把要插入的花完全放进去
这样如果这个区间全为空,那么就直接填满,如果这个区间有被分割的
区间可以满足要插入花的数量,那么操作完成后,整个区间也会被花插满
所以,直接默认整个区间全部清成0即可
2、如果这个是清除花,肯定是要整个区间全部变成1
故,对于情况1、2我们只需要标记这个区间整体清成0或者1即可*/
lazy[rt] = val;
sum[rt] = (r - l + 1) * val;
return ;
}
int m = (l + r)>>1;
Pushdown(rt,m - l + 1,r - m);
if(ql <= m){
Update(ql,qr,val,l,m,rt<<1);
}
if(qr > m){
Update(ql,qr,val,m + 1,r,rt<<1|1);
}
PushUp(rt);
}
int Query(int ql,int qr,int l,int r,int rt)
{
if(ql <= l&&r <= qr){
return sum[rt];
}
int m = (r + l)>>1;
Pushdown(rt,m - l + 1,r - m);
int ans = 0;
if(ql <= m){
ans += Query(ql,qr,l,m,rt<<1);
}
if(qr > m){
ans += Query(ql,qr,m + 1,r,rt<<1|1);
}
return ans;
}
//二分查找满足可以将一定数量花全部插入的最小区间,即恰好把给定的花全部插入
int Search(int x,int n,int f_num)
{
int l = x,r = n,ans = -1;
while(l <= r){
int mid = (r + l)>>1;
int num = Query(x,mid,1,n,1);
if(num >= f_num){
ans = mid;
r = mid - 1;
}
else{
l = mid + 1;
}
}
return ans;
}
void Build(int l,int r,int rt)
{
sum[rt] = r - l + 1;
lazy[rt] = -1;
if(l == r){
return ;
}
int m = (r + l)>>1;
Build(l,m,rt<<1);
Build(m + 1,r,rt<<1|1);
}
int main()
{
int t,n,m;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
Build(1,n,1);
int cnt;
while(m--){
scanf("%d",&cnt);
if(cnt == 1){
int ql,qr,l,f_num;
scanf("%d%d",&l,&f_num);
l++;
int num = Query(l,n,1,n,1);
//最大区间插入花数量为0
if(num == 0){
printf("Can not put any one.\n");
}
else{
ql = Search(l,n,1);
qr = Search(l,n,min(num,f_num));
//表示该区间已经插满花
Update(ql,qr,0,1,n,1);
printf("%d %d\n",ql - 1,qr - 1);
}
}
else{
int l,r;
scanf("%d%d",&l,&r);
l++,r++;
int num = Query(l,r,1,n,1);
printf("%d\n",r - l + 1 - num);
Update(l,r,1,1,n,1);
}
}
cout<<endl;
}
return 0;
}