这道题目很多人用二分+线段树来做,但是(可能我太水了吧)想不到怎么用二分,只好照着常规思路来做
题意:
两种操作:1.从a号花瓶开始插入f朵花,每个花瓶只能有一朵花,且有花的花的花瓶不能被放入 2.清除一个区间内花瓶中的花 注意花瓶的编号是0~n-1
解题思路:
这就是两种不同的区间更新,先设置一个结构体
struct list
{
int num;
int weight;
}tree[4*maxn];
num表示在left和right范围内花瓶中的花的数量,weight权值1表示这个范围内花瓶中都有花,-1表示花瓶中都没有花,0表示有的花瓶中有花有的没有
四个线段树函数:
void build(int i,int left,int right);
void update_add(int i,int left,int right);
void update_del(int i,int ql,int qr,int left,int right);
void pushup(int i,int left,int right);
void pushdown(int i,int left,int right);
build函数将tree数组中的num赋值为0,weight赋值为-1,表示起初花瓶都是空的,update_add函数计算添加花的情况,update_del函数计算去除花的情况,pushup函数更新父节点,pushdown函数更新子节点
if(op==1)
{
scanf("%d%d",&L,&ans);
L++;
R=L+ans-1;l=-1,r=-1;
update_add(1,1,n);
if(r==-1)
printf("Can not put any one.\n");
else
printf("%d %d\n",l-1,r-1);
}
插花的操作,因为花瓶的编号可能为零所以将更新的左边界+1,而右边界是可以改变,随着插花向右增大,最大为n
else if(op==2)
{
int a,b;
scanf("%d%d",&a,&b);
ans=0;
update_del(1,a+1,b+1,1,n);
printf("%d\n",ans);
}
丢花的操作就是一个区间更新,注意边界都要+1
void update_add(int i,int left,int right)
{
if(ans<=0)
return ;
if(r==n)
return ;
if(L<=left&&R>=right&&tree[i].weight)
{
if(!tree[i].num)
{
if(l<0)
l=left;
if(right>r)
r=right;
ans-=right-left+1;
tree[i].num=right-left+1;
tree[i].weight=1;
}
else
{
R+=(right-left+1);
if(R>n)
R=n;
}
return ;
}
if(tree[i].weight)
pushdown(i,left,right);
int mid=(left+right)>>1;
if(L<=mid)
update_add(i<<1,left,mid);
if(R>mid)
update_add(i<<1|1,mid+1,right);
pushup(i,left,right);
}
最关键的是第三个if语句中的,如果逻辑不好就有超时的风险,简单说一下,当这个区间在L和R内且全为1或0时,执行内部的语句,如果全为0,就把花插上更新起点、终点,如果全为1,就就扩大右边界(最大为n)
Alice有N个花瓶(标号为0~ N-1)。当她收到一些花时,她会随机的选择一个瓶子A,从它开始遍历A,A+1, A+2, ..., N-1号瓶子,遇到空瓶子就放一朵花进去,直到花朵放完或没有瓶子,剩下的花将被丢弃。有时,她也会清理标号从A到B的花瓶(A <= B).花瓶里的花会被丢弃。 Input
第一行一个整数T,表示数据组数。
每组数据,第一行一个整数N(1 < N < 50001) and M(1 < M < 50001). N 是花瓶个数, M 是Alice的操作次数. 接下来M行 行3个 整数. 第一个整数K(1 or 2). 如果K=1, 后面跟两个整数 A 和 F . 表示Alice 得到了F 朵花并且把它们放入从A 的花瓶里. 如果K= 2, 后跟两个整数 A 和 B. 表示Alice 清理的花瓶标号范围(A <= B).
对于每个K=1的操作,输出第一朵和最后一朵花放置的花瓶标号。如果没有任何放花的位置,输出'Can not put any one.'.对于K=2的操作,输出丢弃花的个数.
每组数据后输出一个空行.
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 3Sample Output
3 7 2 1 9 4 Can not put any one. 2 6 2 0 9 4 4 5 2 3
#include
#include
#define maxn 50005
struct list
{
int num;
int weight;
}tree[4*maxn];
int ans,l,r,n,L,R;
void build(int i,int left,int right);
void update_add(int i,int left,int right);
void update_del(int i,int ql,int qr,int left,int right);
void pushup(int i,int left,int right);
void pushdown(int i,int left,int right);
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int m;
scanf("%d%d",&n,&m);
build(1,1,n);
for(int i=0;i>1;
build(i<<1,left,mid);
build(i<<1|1,mid+1,right);
}
void update_add(int i,int left,int right)
{
if(ans<=0)
return ;
if(r==n)
return ;
if(L<=left&&R>=right&&tree[i].weight)
{
if(!tree[i].num)
{
if(l<0)
l=left;
if(right>r)
r=right;
ans-=right-left+1;
tree[i].num=right-left+1;
tree[i].weight=1;
}
else
{
R+=(right-left+1);
if(R>n)
R=n;
}
return ;
}
if(tree[i].weight)
pushdown(i,left,right);
int mid=(left+right)>>1;
if(L<=mid)
update_add(i<<1,left,mid);
if(R>mid)
update_add(i<<1|1,mid+1,right);
pushup(i,left,right);
}
void update_del(int i,int ql,int qr,int left,int right)
{
if(ql<=left&&qr>=right)
{
ans+=tree[i].num;
tree[i].num=0;
tree[i].weight=-1;
return ;
}
if(tree[i].weight)
pushdown(i,left,right);
int mid=(left+right)>>1;
if(ql<=mid)
update_del(i<<1,ql,qr,left,mid);
if(qr>mid)
update_del(i<<1|1,ql,qr,mid+1,right);
pushup(i,left,right);
}
void pushup(int i,int left,int right)
{
tree[i].num=tree[i<<1].num+tree[i<<1|1].num;
if(tree[i<<1].num+tree[i<<1|1].num==right-left+1)
tree[i].weight=1;
else if(tree[i<<1].num+tree[i<<1|1].num==0)
tree[i].weight=-1;
}
void pushdown(int i,int left,int right)
{
if(tree[i].weight==1)
{
tree[i<<1].weight=1;
tree[i<<1|1].weight=1;
int mid=(left+right)>>1;
tree[i<<1].num=mid-left+1;
tree[i<<1|1].num=right-mid;
tree[i].weight=0;
}
else if(tree[i].weight==-1)
{
tree[i<<1].weight=-1;
tree[i<<1|1].weight=-1;
tree[i<<1].num=0;
tree[i<<1|1].num=0;
tree[i].weight=0;
}
}