题意:
插花和拔花的过程,1插,2拔,如果一个都不能插输出 “ ...” ,如果能插至少一朵花,但是不够插,就把其余的花扔掉
思路;
lazy标记为1 时表示已空, -1时表示已满,sum表示空瓶子个数,first表示最左边空瓶位置,last表示最右边空瓶位置,-1表示无
自己第一次写的时候感觉的难点在于如何找到区间的右端点,发现kuangbin大神写了个二分,真是强,第一次做先断食用到二分。
具体二分操作是:
枚举右端点的第一个满足条件的位置,即统计l~r的sum(空瓶子个数),找到第一个满足条件的右侧瓶子位置。就可以将(l ~ ??) 转变为 (l ~ r)区间上的区间查询和修改的问题了。
区间特值查询:
之后是一个查(l~r)区间的存储值的问题,就简单多了,即查到(l~r)的第一个非空位置和最后一个非空位置,因为在二分的时候已经确定了r是最优的区间,但是不能直接输出t,各位可以自己体验下第二组数据,这是因为对于可以插,但是不够插的情况来说,二分只是返回了R (n)但是并非最后的第二个值的结果。
区间更新:
对于每次操作,1操作是一个插花的操作,对于l~r的区间都置为空。
2是一个拔花的操作,对于l~r的区间都只能1。
我这里标记的是 空表示不能插, 1表示能插。
sum记载的是区间空瓶子的个数。
总结一下:
昨晚搞了一晚上也没弄明白,因为自己一直都无法判断区间右端点的问题,下次线段树做的时候不管题中的要求是什么,对于区间操作,必须知道区间的始末位置,否则线段树是不能完成的。
#include <stdio.h>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=50005;
struct node
{
int left,right;
int lazy,first,last;
int sum;
}tree[maxn*4];
int n,m;
void push_up(int i)
{
tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
if(tree[i<<1].first!=-1)
tree[i].first=tree[i<<1].first;
else tree[i].first=tree[i<<1|1].first;
if(tree[i<<1|1].last!=-1)
tree[i].last=tree[i<<1|1].last;
else
tree[i].last=tree[i<<1].last;
}
void push_down(int i)
{
if(tree[i].lazy==1)
{
tree[i<<1].first=tree[i<<1].left;
tree[i<<1].last=tree[i<<1].right;
tree[i<<1].sum=tree[i<<1].right-tree[i<<1].left+1;
tree[i<<1].lazy=1;
tree[i<<1|1].first=tree[i<<1|1].left;
tree[i<<1|1].last=tree[i<<1|1].right;
tree[i<<1|1].sum=tree[i<<1|1].right-tree[i<<1|1].left+1;
tree[i<<1|1].lazy=1;
}
if(tree[i].lazy==-1)
{
tree[i<<1].first=-1;
tree[i<<1].last=-1;
tree[i<<1].sum=0;
tree[i<<1].lazy=-1;
tree[i<<1|1].first=-1;
tree[i<<1|1].last=-1;
tree[i<<1|1].sum=0;
tree[i<<1|1].lazy=-1;
}
tree[i].lazy=0;
}
// lazy标记为1 时表示已空, -1时表示已满,sum表示空瓶子个数,first表示最左边空瓶位置,last表示最右边空瓶位置,-1表示无
void build(int i,int left,int right)
{
tree[i].left=left,tree[i].right=right;
tree[i].first=left,tree[i].last=right;
tree[i].lazy=0,tree[i].sum=right-left+1;
if(left==right)
return ;
int mid=(tree[i].left+tree[i].right)>>1;
build(i<<1,left,mid);
build(i<<1|1,mid+1,right);
}
void update(int i,int left,int right,int w)
{
if(tree[i].left==left&&tree[i].right==right)
{
if(w==0)
{
tree[i].sum=0,tree[i].first=-1,tree[i].last=-1;
tree[i].lazy=-1;
return ;
}
else
{
tree[i].sum=right-left+1,tree[i].first=left,tree[i].last=right;
tree[i].lazy=1;
return ;
}
}
push_down(i);
int mid=(tree[i].left+tree[i].right)>>1;
if(right<=mid)
update(i<<1,left,right,w);
else if(left>mid)
update(i<<1|1,left,right,w);
else
{
update(i<<1,left,mid,w);
update(i<<1|1,mid+1,right,w);
}
push_up(i);
return ;
}
int sum(int i,int left,int right)
{
if(tree[i].left==left&&tree[i].right==right)
return tree[i].sum;
push_down(i);
int mid=(tree[i].left+tree[i].right)>>1;
if(right<=mid)
return sum(i<<1,left,right);
else if(left>mid)
return sum(i<<1|1,left,right);
else
return sum(i<<1,left,mid)+sum(i<<1|1,mid+1,right);
}
int queryFirst_notEmpty(int i,int left,int right)
{
if(tree[i].left==left&&tree[i].right==right)
{
return tree[i].first;
}
push_down(i);
int mid=(tree[i].left+tree[i].right)>>1;
int ans;
if(right<=mid)
ans=queryFirst_notEmpty(i<<1,left,right);
else if(left>mid)
ans=queryFirst_notEmpty(i<<1|1,left,right);
else
{
ans=queryFirst_notEmpty(i<<1,left,mid);
if(ans==-1)
ans=queryFirst_notEmpty(i<<1|1,mid+1,right);
}
return ans;
}
int queryLast_notEmpty(int i,int left,int right)
{
if(tree[i].left==left&&tree[i].right==right)
return tree[i].last;
push_down(i);
int mid=(tree[i].left+tree[i].right)>>1;
int ans;
if(right<=mid)
ans=queryLast_notEmpty(i<<1,left,right);
else if(left>mid)
ans=queryLast_notEmpty(i<<1|1,left,right);
else
{
ans=queryLast_notEmpty(i<<1|1,mid+1,right);
if(ans==-1)
ans=queryLast_notEmpty(i<<1,left,mid);
}
return ans;
}
int bisearch(int A,int F)
{
if(sum(1,A,n)==0)return -1;
if(sum(1,A,n)<=F)return n;
int l= A,r = n;
int ans=A;
while(l<=r)
{
int mid = (l+r)/2;
if(sum(1,A,mid)>=F)
{
ans = mid;
r = mid-1;
}
else l = mid+1;
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
build(1,1,n);
int op,u,v;
while(m--)
{
scanf("%d%d%d",&op,&u,&v);
if(op == 1)
{
u++;
int t = bisearch(u,v);
if(t==-1)
{
printf("Can not put any one.\n");
continue;
}
printf("%d %d\n",queryFirst_notEmpty(1,u,t)-1,queryLast_notEmpty(1,u,t)-1);
update(1,u,t,0);
}
else
{
u++,v++;
printf("%d\n",v-u+1-sum(1,u,v));
update(1,u,v,1);
}
}
printf("\n");
}
return 0;
}
/*
1
10 6
1 4 1
1 2 3
*/