【题意】初始有n个空花瓶,然后有q个操作,1 x y,从x开始插花,插够k个即可。2 x y,把x,y区间有有花的花瓶全部清空。
【解题方法】
线段树维护剩余空花瓶的个数
第一种操作二分≥1的最左边的位置,二分≥k的最左边位置
第二种直接更新就好啦
复杂度是O(n+mlog2n)
【AC代码】
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=5e5+5;
int n;
struct Segment{
int sum[maxn<<2],lazy[maxn<<2];
void Build(int l,int r,int rt)
{
sum[rt]=r-l+1;
lazy[rt]=-1;
if(l==r) return ;
int mid=(l+r)/2;
Build(l,mid,rt*2);
Build(mid+1,r,rt*2+1);
}
void pushup(int rt){
sum[rt]=sum[rt*2]+sum[rt*2+1];
}
void pushdown(int rt,int m){
if(lazy[rt]!=-1){
lazy[rt*2]=lazy[rt*2+1]=lazy[rt];
sum[rt*2]=lazy[rt]*(m-(m>>1));
sum[rt*2+1]=lazy[rt]*(m>>1);
lazy[rt]=-1;
}
}
int update(int L,int R,int v,int l,int r,int rt)
{
if(L<=l&&r<=R){
int ret=sum[rt];
sum[rt]=v*(r-l+1);
lazy[rt]=v;
return ret;
}
int mid=(l+r)/2;
pushdown(rt,r-l+1);
int ret=0;
if(L<=mid) ret+=update(L,R,v,l,mid,rt*2);
if(mid<R) ret+=update(L,R,v,mid+1,r,rt*2+1);
pushup(rt);
return ret;
}
int queryans(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R){
return sum[rt];
}
pushdown(rt,r-l+1);
int ret=0;
int mid=(l+r)/2;
if(L<=mid) ret+=queryans(L,R,l,mid,rt*2);
if(mid<R) ret+=queryans(L,R,mid+1,r,rt*2+1);
return ret;
}
}Tree;
int get(int st,int k)
{
int l=st,r=n;
while(l<=r){
int m=(l+r)/2;
if(Tree.queryans(st,m,1,n,1)>=k) r=m-1;
else l=m+1;
}
return l;
}
int main()
{
int T,q;
scanf("%d",&T);
while(T--)
{
int op,x,y;
scanf("%d%d",&n,&q);
Tree.Build(1,n,1);
while(q--)
{
scanf("%d%d%d",&op,&x,&y);
if(op==1){
int all=Tree.queryans(x+1,n,1,n,1);
if(all==0){
puts("Can not put any one.");
}
else{
int l=get(x+1,1);
int r=get(x+1,min(all,y));
//cout<<l<<" "<<r<<endl;
Tree.update(l,r,0,1,n,1);
printf("%d %d\n",l-1,r-1);
}
}else{
int tt=Tree.update(x+1,y+1,1,1,n,1);
int ans=y-x+1-tt;
printf("%d\n",ans);
}
}
printf("\n");
}
return 0;
}