题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4614
题目大意:
有n个空花瓶,编号 0~n-1,有两种操作,操作一,从A花瓶开始放F朵花,每个花瓶若没有花就放一朵,从A开始到n-1依次放,若没有花了或者遍历完花瓶了就不放了,要求输出第一朵被放的位置和最后一朵被放的位置,若没有花被放输出特定语句。操作二,清空A-B花瓶的花,输出被清理花的个数。
解题思路:
很简单的线段树区间更新,区间求和,但是要求对二分比较熟悉,一共要二分三次。
因为只要找到起始和终止的位置,所以依次找肯定超时,二分找就可以了。
找到第一朵花被放的位置,即第一个空的花瓶(左边界)
int askl(int a)//找到起始位置
{
int l=a,r=n-1;
while(l<r)
{
int mid=(l+r)>>1;
if(mid-l+1>query(0,n-1,1,l,mid))
r=mid;
else
l=mid+1;
}
return l;
}
若花未被放完找到最后一个放花的位置(右边界),这里mid=(l+r+1)>>1,否则会死循环,博主就卡在这了QAQ。
int askr(int a)//找到终止位置
{
int l=a,r=n-1;
while(l<r)
{
int mid=(l+r+1)>>1;
if(r-mid+1>query(0,n-1,1,mid,r))
l=mid;
else
r=mid-1;
}
return l;
}
若花被放完找到最后一个放花的位置。
int askrr(int a,int b)//放得完的终止位置
{
int l=a,r=n-1;
while(l<r)
{
int mid=(l+r)>>1;
if(check(a,mid,b))
r=mid;
else
l=mid+1;
}
return l;
}
其它就是正常的区间更新,区间求和,没什么好说的了。
完整AC代码
#include <iostream>
#include <stdio.h>
using namespace std;
const int maxn=5e4+5;
int tree[maxn<<2];
int lazy[maxn<<2];
int T,n,m;
void push_up(int k)
{
tree[k]=tree[k<<1]+tree[k<<1|1];
}
void push_down(int l,int r,int k)
{
if(lazy[k]==-1)
return;
int mid=(l+r)>>1;
tree[k<<1]=lazy[k]*(mid-l+1);
tree[k<<1|1]=lazy[k]*(r-mid);
lazy[k<<1]=lazy[k<<1|1]=lazy[k];
lazy[k]=-1;
}
void build(int l,int r,int k)
{
lazy[k]=-1;
if(l==r)
{
tree[k]=0;
return;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
push_up(k);
}
void update(int l,int r,int k,int ll,int rr,int w)
{
if(ll<=l&&rr>=r)
{
tree[k]=(r-l+1)*w;
lazy[k]=w;
return;
}
push_down(l,r,k);
int mid=(l+r)>>1;
if(ll<=mid)
update(l,mid,k<<1,ll,rr,w);
if(rr>mid)
update(mid+1,r,k<<1|1,ll,rr,w);
push_up(k);
}
int query(int l,int r,int k,int ll,int rr)
{
if(ll<=l&&rr>=r)
{
return tree[k];
}
push_down(l,r,k);
int mid=(l+r)>>1;
int ans=0;
if(ll<=mid)
ans+=query(l,mid,k<<1,ll,rr);
if(rr>mid)
ans+=query(mid+1,r,k<<1|1,ll,rr);
return ans;
}
bool check(int l,int r,int k)
{
int s=r-l+1-query(0,n-1,1,l,r);
//cout<<"l "<<l<<" r "<<r<<" "<<query(0,n-1,1,l,r)<<endl;
return s>=k;
}
int askl(int a)//找到起始位置
{
int l=a,r=n-1;
while(l<r)
{
int mid=(l+r)>>1;
if(mid-l+1>query(0,n-1,1,l,mid))
r=mid;
else
l=mid+1;
}
return l;
}
int askr(int a)//找到终止位置
{
int l=a,r=n-1;
while(l<r)
{
int mid=(l+r+1)>>1;
if(r-mid+1>query(0,n-1,1,mid,r))
l=mid;
else
r=mid-1;
}
return l;
}
int askrr(int a,int b)//放得完的终止位置
{
int l=a,r=n-1;
while(l<r)
{
int mid=(l+r)>>1;
if(check(a,mid,b))
r=mid;
else
l=mid+1;
}
return l;
}
int opt,a,b;
int first,last;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
build(0,n-1,1);
while(m--)
{
scanf("%d",&opt);
if(opt==1)
{
scanf("%d %d",&a,&b);
int tag=n-a-query(0,n-1,1,a,n-1);
//cout<<n-a<<" "<<query(0,n-1,1,a,n-1)<<endl;
if(!tag)
puts("Can not put any one.");
else
{
first=askl(a);
//cout<<"f "<<first<<endl;
if(tag==1)
{
last=first;
printf("%d %d\n",first,last);
}
else
{
if(tag>=b)//放得完
last=askrr(a,b);
else//放不完
last=askr(a);
printf("%d %d\n",first,last);
}
//cout<<"l "<<last<<endl;
update(0,n-1,1,first,last,1);
}
}
else
{
scanf("%d %d",&a,&b);
printf("%d\n",query(0,n-1,1,a,b));
update(0,n-1,1,a,b,0);
}
}
printf("\n");
}
return 0;
}