题目链接:https://acm.hdu.edu.cn/showproblem.php?pid=4614
先给出中文翻译吧:
爱丽丝是如此受欢迎,以至于她每天都能收到许多鲜花。她有 N 个花瓶,编号从 0 到 N-1。当她收到一些花时,她会试着把它们放在花瓶里,一花一瓶。她随机选择了花瓶 A 并尝试在花瓶中放入一朵花。如果花瓶里没有花,她会在里面放一朵花,否则她跳过这个花瓶。然后她会尝试放入花瓶 A+1、A+2、...、N-1,直到没有花或她尝试过花瓶 N-1。剩下的花将被丢弃。当然,有时她会打扫花瓶。因为花瓶太多,她随机选择清洗编号为A到B(A <= B)的花瓶。清洗过的花瓶中的花将被丢弃。
输入
第一行包含一个整数 T,表示测试用例的数量。
对于每个测试用例,第一行包含两个整数 N(1 < N < 50001) 和 M(1 < M < 50001)。N是花瓶的数量,M是Alice的操作。接下来的 M 行中的每一行都包含三个整数。一行的第一个整数是 K(1 或 2)。如果 K 是 1,则后面跟着两个整数 A 和 F。这意味着爱丽丝收到了 F 朵花,并尝试先将一朵花放入花瓶 A 中。如果 K 是 2,则后面跟着两个整数 A 和 B。这意味着主人想清洁从 A 到 B(A <= B)编号的花瓶。
输出
对于 K 为 1 的每个操作,输出 Alice 放第一朵花和最后一朵花的花瓶的位置,用空格隔开。如果她不能放任何一个,那么输出'不能放任何一个.'。对于 K 为 2 的每个操作,输出丢弃的花数。
每个测试用例后输出一个空行。
分析:对于操作2,就是简单的区间修改,关键是如何处理操作1,我们可以先找一下从给定编号的花瓶到编号为n-1的花瓶一共还能放几朵花,如果是0,就直接输出 Can not put any one. 如果可放花的数量多于所需放花的数量,那我们需要放几朵花就放几朵花,否则能放几朵花就放几朵花,我们可以通过二分来找放花的起点和终点,具体看代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int N=3e5+10;
int sum[N],l[N],r[N],lazy[N];
void pushup(int id)
{
sum[id]=sum[id<<1]+sum[id<<1|1];
}
void pushdown(int id)
{
if(lazy[id]!=-1)//涉及到区间赋值为0操作,lazy数组初始化为-1
{
sum[id<<1]=(r[id<<1]-l[id<<1]+1)*lazy[id];
sum[id<<1|1]=(r[id<<1|1]-l[id<<1|1]+1)*lazy[id];
lazy[id<<1]=lazy[id];
lazy[id<<1|1]=lazy[id];
lazy[id]=-1;
}
}
void build(int id,int L,int R)
{
//涉及到区间赋值为0操作,lazy数组初始化为-1
l[id]=L;r[id]=R;sum[id]=0;lazy[id]=-1;
if(L==R) return ;
int mid=L+R>>1;
build(id<<1,L,mid);
build(id<<1|1,mid+1,R);
pushup(id);
}
int query_interval(int id,int L,int R)
{
if(l[id]>R||r[id]<L) return 0;
if(l[id]>=L&&r[id]<=R) return sum[id];
pushdown(id);
return query_interval(id<<1,L,R)+query_interval(id<<1|1,L,R);
}
void update_interval(int id,int L,int R,int val)
{
if(l[id]>R||r[id]<L) return ;
if(l[id]>=L&&r[id]<=R)
{
sum[id]=val*(r[id]-l[id]+1);
lazy[id]=val;
return ;
}
pushdown(id);
update_interval(id<<1,L,R,val);
update_interval(id<<1|1,L,R,val);
pushup(id);
}
int main()
{
int T,n,m;
cin>>T;
while(T--)
{
scanf("%d%d",&n,&m);
build(1,1,n);
int x,y,op;
while(m--)
{
scanf("%d%d%d",&op,&x,&y);
if(op==1)
{
x++;//将区间变为1~n
int t=min(y,n-x+1-query_interval(1,x,n));
if(!t)
{
printf("Can not put any one.\n");
continue;
}
//二分找起点
int ll=x,rr=n;
while(ll<rr)
{
int mid=ll+rr>>1;
if(mid-x+1-query_interval(1,x,mid)>=1) rr=mid;
else ll=mid+1;
}
printf("%d ",ll-1);
//二分找终点
ll=x,rr=n;
while(ll<rr)
{
int mid=ll+rr>>1;
if(mid-x+1-query_interval(1,x,mid)>=t) rr=mid;
else ll=mid+1;
}
printf("%d\n",ll-1);
//别忘了查询到起点和终点后将此区间内都装满花
update_interval(1,x,ll,1);
}
else
{
x++;y++;//将区间变为1~n
printf("%d\n",query_interval(1,x,y));
update_interval(1,x,y,0);
}
}
printf("\n");
}
return 0;
}