Problem Description
Alice is so popular that she can receive many flowers everyday. She has N vases numbered from 0 to N-1. When she receive some flowers, she will try to put them in the vases, one flower in one vase. She randomly choose the vase A and try to put a flower in the vase. If the there is no flower in the vase, she will put a flower in it, otherwise she skip this vase. And then she will try put in the vase A+1, A+2, …, N-1, until there is no flower left or she has tried the vase N-1. The left flowers will be discarded. Of course, sometimes she will clean the vases. Because there are too many vases, she randomly choose to clean the vases numbered from A to B(A <= B). The flowers in the cleaned vases will be discarded.
Input
The first line contains an integer T, indicating the number of test cases.
For each test case, the first line contains two integers N(1 < N < 50001) and M(1 < M < 50001). N is the number of vases, and M is the operations of Alice. Each of the next M lines contains three integers. The first integer of one line is K(1 or 2). If K is 1, then two integers A and F follow. It means Alice receive F flowers and try to put a flower in the vase A first. If K is 2, then two integers A and B follow. It means the owner would like to clean the vases numbered from A to B(A <= B).
Output
For each operation of which K is 1, output the position of the vase in which Alice put the first flower and last one, separated by a blank. If she can not put any one, then output ‘Can not put any one.’. For each operation of which K is 2, output the number of discarded flowers.
Output one blank line after each test case.
Sample Input
2
10 5
1 3 5
2 4 5
1 1 8
2 3 6
1 8 8
10 6
1 2 5
2 3 4
1 0 8
2 2 5
1 4 4
1 2 3
Sample Output
[pre]3 7
2
1 9
4
Can not put any one.
2 6
2
0 9
4
4 5
2 3
[/pre]
题意
有0~n-1 n个花瓶,m次操作,每次操作输入三个数k,x,y。
k为1时,表示需要从第x个花瓶开始,向x+1 x+2…中空花瓶插花,如果有空花瓶的话,输出第一个插花位置与最后一个插花位置,如果没有空花瓶,输出Can not put any one.
k为2时,表示从第x个花瓶开始到第y个花瓶结束,所有花瓶中的花清空,并统计有花的花瓶个数
思路
刚开始很懵逼,完全没有思路,看了大佬的代码思路才知道怎么做。感谢大佬!!!!
由于花瓶序列是0~n-1,所有可以将它向后平移一个单位.将空花瓶定义为1,有花的花瓶定义为0.
清空与插花的操作就不在多说,这里只说一下如何判断第一个与最后一个插花位置。
方法一:
因为我们要确定第一个花瓶的位置,那么我们只需要在一颗树的左子树中查找在x~n的范围内是否有1个空花瓶(因为我们需要的是第一个空花瓶的位置,所有只需要1个空花瓶),如果有那么第一个空花瓶就在这棵树的左子树中,反之则在右子树中,如此下去直至L等于R,便查找到了第一个空花瓶。
现在查找最后一个空花瓶,由于我们不确定x-n中是否足够y个空花瓶,所有需要计算x~n空花瓶数量t,取num=min(t,y)。
同样的道理,我们首先查找一棵树的左子树在x~n的范围内空花瓶数量(ans)是否满足num,若满足则继续查找;若不满足则查找右子树中是否满足num-ans(由于左子树足够ans个空花瓶,那么我还需要从右子树中找num-ans即可)。如此下去,直至L==R,便查找到了最后一个空花瓶。
方法二:
二分答案,同样是查找x~n中空花瓶的数量。
判断第一个空花瓶位置时,判断x~n中左半边是否有1个空花瓶,若有,继续二分,反之判断右半边,直至L等于R。
判断第最后个空花瓶位置时,判断x~n中左半边是否满足num个空花瓶(与方法一中的num相同),若满足继续二分反之判断右半边是否满足(num-ans),直至L==R。
总结与分析:
1.清空花瓶与插花的过程中,忘记回溯修改父亲节点的值。
2.在修改节点值时,必须同时修改tree[rt]与lazy[rt],而不能只修改lazy[rt],在pushdown中修改tree[rt].
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 51000;
int tree[MAXN<<2],lazy[MAXN<<2];
void pushdown(int rt,int L,int R)
{
lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
if(lazy[rt]){
tree[rt<<1]=((L+R)>>1)-L+1;
tree[rt<<1|1]=R-((L+R)>>1);
}
else{
tree[rt<<1]=0;
tree[rt<<1|1]=0;
}
lazy[rt]=-1;
return ;
}
void build(int rt,int L,int R)
{
lazy[rt]=-1;
if(L==R){
tree[rt]=1;
return ;
}
int Mid = (L+R)>>1;
build(rt<<1,L,Mid);
build(rt<<1|1,Mid+1,R);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void update(int rt,int L,int R,int l,int r)
{
if(l<=L&&R<=r){
tree[rt]=0;
lazy[rt]=0;
return ;
}
int Mid = (L+R)>>1;
if(lazy[rt]!=-1) pushdown(rt,L,R);
if(l<=Mid) update(rt<<1,L,Mid,l,r);
if(Mid<r) update(rt<<1|1,Mid+1,R,l,r);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
int query(int rt,int L,int R,int l,int r)
{
if(l>R||r<L) return 0;
if(l<=L&&R<=r)
return tree[rt];
if(lazy[rt]!=-1) pushdown(rt,L,R);
int Mid = (L+R)>>1;
int ans=0;
if(l<=Mid)
ans+=query(rt<<1,L,Mid,l,r);
if(Mid<r)
ans+=query(rt<<1|1,Mid+1,R,l,r);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
return ans;
}
void Clear(int rt,int L,int R,int l,int r)
{
if(l<=L&&R<=r){
tree[rt]=R-L+1;
lazy[rt]=1;
return ;
}
if(lazy[rt]!=-1) pushdown(rt,L,R);
int Mid = (L+R)>>1;
if(l<=Mid) Clear(rt<<1,L,Mid,l,r);
if(Mid<r) Clear(rt<<1|1,Mid+1,R,l,r);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
int ask(int rt,int L,int R,int l,int r,int num)
{
if(L==R)
return L;
if(lazy[rt]!=-1) pushdown(rt,L,R);
int Mid = (L+R)>>1;
int t = query(rt<<1,L,Mid,l,r);
if(num<=t) return ask(rt<<1,L,Mid,l,r,num);
return ask(rt<<1|1,Mid+1,R,l,r,num-t);
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
build(1,1,n);
while(m--){
int k,x,y;
cin>>k>>x>>y;
if(k==1){
x++;
int t=query(1,1,n,x,n);
if(t==0)
printf("Can not put any one.\n");
else{
int l=ask(1,1,n,x,n,1);
int r=ask(1,1,n,x,n,min(t,y));
printf("%d %d\n",l-1,r-1);
update(1,1,n,l,r);
}
}
else{
x++;y++;
printf("%d\n",y-x+1-query(1,1,n,x,y));
Clear(1,1,n,x,y);
}
}
printf("\n");
}
return 0;
}