题目大意
有 \(n\) 个座位,\(m\) 次操作。
\(\rm A\) 操作:将 \(a\) 名客人安置到最左的连续 \(a\) 个空位中,没有则不操作。
\(\rm L\) 操作:\([a,b]\) 的客人离开。
求 \(\rm A\) 操作中所有不操作的次数。
题目分析
和 \(\verb!P2894!\) 很像。注意这道题 \(\rm L\) 操作是针对区间 \([l,r]\),\(\verb!P2894!\) 是针对区间 \([l,l+x-1]\)。这里坑了我两天。
定义 \(lmax\) 表示从左开始的最大连续空位数,从右开始的连续最大空位数,以及该区间的最大连续空位数 \(max\)。
之所以定义 \(lmax,rmax\),是因为我们从该区间扩展的时候不能只靠 \(max\),也就是说该区间的 \(max\) 不等于左儿子和右儿子的 \(max\) 之和。举个例子:
区间 \([1,8]\)(\(0\) 表示空位,\(1\) 表示非空位):0 0 0 1 0 0 0 1
。\(max[1,8]\neq max[1,4]+max[5,8]\)。但是用 \(lmax,rmax\) 就可以解决了:
inline void pushup(int p)
{
node[p].Max=max(node[ls(p)].Max,max(node[rs(p)].Max,node[ls(p)].rmax+node[rs(p)].lmax));
node[p].lmax=node[ls(p)].Max==(node[ls(p)].r-node[ls(p)].l+1)?node[ls(p)].Max+node[rs(p)].lmax:node[ls(p)].lmax;
node[p].rmax=node[rs(p)].Max==(node[rs(p)].r-node[rs(p)].l+1)?node[rs(p)].Max+node[ls(p)].rmax:node[rs(p)].rmax;
}
对于修改操作,我们仍然使用懒标记。\(tag=1\) 表示非空位,\(tag=0\) 表示空位。
于是可以这样:
inline void pushdown(int p)
{
if(node[p].tag==0)
{
node[ls(p)].tag=node[rs(p)].tag=0;
node[ls(p)].Max=node[ls(p)].lmax=node[ls(p)].rmax=node[ls(p)].r-node[ls(p)].l+1;
node[rs(p)].Max=node[rs(p)].lmax=node[rs(p)].rmax=node[rs(p)].r-node[rs(p)].l+1;
}
else if(node[p].tag==1)
{
node[ls(p)].tag=node[rs(p)].tag=1;
node[ls(p)].Max=node[ls(p)].lmax=node[ls(p)].rmax=0;
node[rs(p)].Max=node[rs(p)].lmax=node[rs(p)].rmax=0;
}
node[p].tag=-1;
}
修改操作没啥好讲的,重点讲讲查询操作。
我们查询操作是为了返回左端点值,如果左儿子装得下 \(x\) 个座位,那么递归到左儿子去;如果跨越左右儿子的空位数装得下 \(x\) 个座位,那么返回左端点位置;否则递归到右儿子去。
inline int query(int p,int k)
{
if(node[p].l==node[p].r)
{
return node[p].l;
}
Segment_Tree::pushdown(p);
int mid=node[p].l+node[p].r>>1;
if(node[ls(p)].Max>=k)
{
return Segment_Tree::query(ls(p),k);
}
if(node[ls(p)].rmax+node[rs(p)].lmax>=k)
{
return node[ls(p)].r-node[ls(p)].rmax+1;
}
else
{
return Segment_Tree::query(rs(p),k);
}
}
代码
完整代码:
//2022/1/31
//2022/2/1
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <climits>//need "INT_MAX","INT_MIN"
#include <cstring>//need "memset"
#include <algorithm>
#define enter() putchar(10)
#define debug(c,que) cerr<<#c<<" = "<<c<<que
#define cek(c) puts(c)
#define blow(arr,st,ed,w) for(register int i=(st);i<=(ed);i++)cout<<arr[i]<<w;
#define speed_up() cin.tie(0),cout.tie(0)
#define endl "\n"
#define Input_Int(n,a) for(register int i=1;i<=n;i++)scanf("%d",a+i);
#define Input_Long(n,a) for(register long long i=1;i<=n;i++)scanf("%lld",a+i);
#define mst(a,k) memset(a,k,sizeof(a))
namespace Newstd
{
inline int read()
{
int x=0,k=1;
char ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
{
k=-1;
}
ch=getchar();
}
while(ch>='0' && ch<='9')
{
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x*k;
}
inline void write(int x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
{
write(x/10);
}
putchar(x%10+'0');
}
}
using namespace Newstd;
using namespace std;
const int ma=5e5+5;
struct Node
{
int l,r;
int lmax,rmax;//from left,from right
int tag,Max;
//if tag = 0: get out
//if tag = 1: come in
};
Node node[ma<<2];
int n,m;
namespace Segment_Tree
{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
inline void pushup(int p)
{
node[p].Max=max(node[ls(p)].Max,max(node[rs(p)].Max,node[ls(p)].rmax+node[rs(p)].lmax));
node[p].lmax=node[ls(p)].Max==(node[ls(p)].r-node[ls(p)].l+1)?node[ls(p)].Max+node[rs(p)].lmax:node[ls(p)].lmax;
node[p].rmax=node[rs(p)].Max==(node[rs(p)].r-node[rs(p)].l+1)?node[rs(p)].Max+node[ls(p)].rmax:node[rs(p)].rmax;
}
inline void build(int p,int l,int r)
{
node[p].l=l,node[p].r=r;
if(node[p].l==node[p].r)
{
node[p].lmax=node[p].rmax=node[p].Max=1;
return;
}
int mid=node[p].l+node[p].r>>1;
Segment_Tree::build(ls(p),l,mid);
Segment_Tree::build(rs(p),mid+1,r);
Segment_Tree::pushup(p);
}
inline void pushdown(int p)
{
if(node[p].tag==0)
{
node[ls(p)].tag=node[rs(p)].tag=0;
node[ls(p)].Max=node[ls(p)].lmax=node[ls(p)].rmax=node[ls(p)].r-node[ls(p)].l+1;
node[rs(p)].Max=node[rs(p)].lmax=node[rs(p)].rmax=node[rs(p)].r-node[rs(p)].l+1;
}
else if(node[p].tag==1)
{
node[ls(p)].tag=node[rs(p)].tag=1;
node[ls(p)].Max=node[ls(p)].lmax=node[ls(p)].rmax=0;
node[rs(p)].Max=node[rs(p)].lmax=node[rs(p)].rmax=0;
}
node[p].tag=-1;
}
inline void update(int x,int y,int p,int k)
{
if(x<=node[p].l && node[p].r<=y)
{
if(k==0)
{
node[p].Max=node[p].lmax=node[p].rmax=node[p].r-node[p].l+1;
}
else
{
node[p].Max=node[p].lmax=node[p].rmax=0;
}
node[p].tag=k;
return;
}
Segment_Tree::pushdown(p);
int mid=node[p].l+node[p].r>>1;
if(x<=mid)
{
Segment_Tree::update(x,y,ls(p),k);
}
if(y>mid)
{
Segment_Tree::update(x,y,rs(p),k);
}
Segment_Tree::pushup(p);
}
inline int query(int p,int k)
{
if(node[p].l==node[p].r)
{
return node[p].l;
}
Segment_Tree::pushdown(p);
int mid=node[p].l+node[p].r>>1;
if(node[ls(p)].Max>=k)
{
return Segment_Tree::query(ls(p),k);
}
if(node[ls(p)].rmax+node[rs(p)].lmax>=k)
{
return node[ls(p)].r-node[ls(p)].rmax+1;
}
else
{
return Segment_Tree::query(rs(p),k);
}
}
#undef ls
#undef rs
}
int main(void)
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
n=read(),m=read();
Segment_Tree::build(1,1,n);
int ans=0;
for(register int i=1;i<=m;i++)
{
char ch[3];
scanf("%s",ch);
int x=read();
if(ch[0]=='A')
{
if(node[1].Max>=x)
{
int l=Segment_Tree::query(1,x);
Segment_Tree::update(l,l+x-1,1,1);
}
else
{
ans++;
}
}
else
{
int y=read();
Segment_Tree::update(x,y,1,0);
}
}
printf("%d\n",ans);
return 0;
}