Vases and Flowers

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
3 7
2
1 9
4
Can not put any one.

2 6
2
0 9
4
4 5
2 3


很简单的一道线段树,但是由于自己的sb,导致调了好久。。。。。。。


首先:
对于操作1,我们可以判断 [a,n] 的空位有多少个。
即: n - a + 1 - sum
然后就分为这几种情况:

  1. 一个空位都没有了,直接输出即可。
  2. 可以放完鲜花,我们直接二分 a 到 mid 的和等于数量 b即可。(当然首先我们要二分第一个空位的位置,开始放花)
  3. 不能放完鲜花,我们直接二分最后一个空位的位置即可。(当然首先我们要二分第一个空位的位置,开始放花)

对于操作2,我们直接线段树区间更新清空即可。


AC代码:

#pragma GCC optimize(2)
#include
//#define int long long
using namespace std;
const int N=5e4+10;
int T,n,m;
struct node{
	int l,r,sum,add;
}t[N<<2];
inline void push_up(int p){
	t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
}
inline void push_down(int p){
	if(t[p].add!=-1){
		t[p<<1].add=t[p<<1|1].add=t[p].add;
		t[p<<1].sum=(t[p<<1].r-t[p<<1].l+1)*t[p].add;
		t[p<<1|1].sum=(t[p<<1|1].r-t[p<<1|1].l+1)*t[p].add;
		t[p].add=-1;
	}
}
void build(int p,int l,int r){
	t[p].l=l; t[p].r=r; t[p].sum=0;	t[p].add=-1;
	if(l==r)	return ;
	int mid=l+r>>1;
	build(p<<1,l,mid);	build(p<<1|1,mid+1,r);
	push_up(p);
}
void change(int p,int l,int r,int v){
	if(t[p].l==l&&t[p].r==r){
		t[p].sum=(t[p].r-t[p].l+1)*v;	t[p].add=v;	return ;
	}
	push_down(p);	int mid=t[p].l+t[p].r>>1;
	if(r<=mid)	change(p<<1,l,r,v);
	else if(l>mid)	change(p<<1|1,l,r,v);
	else	change(p<<1,l,mid,v),change(p<<1|1,mid+1,r,v);
	push_up(p);
}
int ask(int p,int l,int r){
	if(t[p].l==l&&t[p].r==r)	return t[p].sum;
	push_down(p);	int mid=t[p].l+t[p].r>>1;
	if(r<=mid)	return ask(p<<1,l,r);
	else if(l>mid)	return ask(p<<1|1,l,r);
	else	return ask(p<<1,l,mid)+ask(p<<1|1,mid+1,r);
}
int askl(int p,int l,int r){
	while(l<r){
		int mid=l+r>>1;
		if(mid-l+1>ask(1,l,mid))	r=mid;
		else	l=mid+1;
	}
	return l;
}
int askr(int p,int l,int r){
	while(l<r){
		int mid=l+r+1>>1;
		if(r-mid+1>ask(1,mid,r))	l=mid;
		else	r=mid-1;
	}
	return l;
}
inline int check(int l,int mid,int k){
	int res=mid-l+1-ask(1,l,mid);//空 
	return res>=k;
}
int bsearch(int a,int s){
	int l=a,r=n;
	while(l<r){
		int mid=l+r>>1;
		if(check(a,mid,s))	r=mid;
		else	l=mid+1;
	}
	return l;
}
signed main(){
	cin>>T;
	while(T--){
		cin>>n>>m;	build(1,1,n);
		while(m--){
			int k,a,b;	cin>>k>>a>>b;	a++;
			if(k==1){
				int cnt=n-a+1-ask(1,a,n);//cnt为空位 
				if(cnt)	a=askl(1,a,n);//找到新的位置 
				if(!cnt){//无空位 
					puts("Can not put any one.");
				}else if(cnt>=b){//可以放完 
					int r=bsearch(a,b);	
					printf("%d %d\n",a-1,r-1);	change(1,a,r,1);
				}else{
					printf("%d %d\n",a-1,askr(1,a,n)-1);
					change(1,a,n,1);//不能放完,就要找到最后一个空位 	
				}
			}else{
				printf("%d\n",ask(1,a,b+1));	change(1,a,b+1,0);//清洗花瓶 
			}
		}
		puts("");
	}
	return 0;
}

你可能感兴趣的:(线段树)