[USACO13JAN]座位Seating
线段树
题解:
线段树维护区最长全0区间。
支持区间修改为一个值。
查询的时候,先看看左区间是否有满足要求的,有就往左走;
否则看看跨越左区间和右区间的那段是否满足要求,满足就选它;
否则往右走。(在一开始就特判操作失败的情况后,则此时右边一定有)
一定别漏了pushdown!
Code:
#include <iostream>
#include <cstring>
#include <cstdio>
#define lch(x) (x<<1)
#define rch(x) ((x<<1)|1)
using namespace std;
const int N = 300005;
int n,m,ans;
struct Node{
int l,r,len,a,b,mx,tag;
} pool[N<<2];
void update(int x){
Node &t=pool[x];
if(t.tag!=-1){
if(t.tag==0) t.a=t.b=t.mx=t.len;
else t.a=t.b=t.mx=0;
}
else{
Node &lc=pool[lch(x)], &rc=pool[rch(x)];
t.mx=max(lc.b+rc.a,max(lc.mx,rc.mx));
t.a=lc.a; if(lc.a==lc.len)t.a+=rc.a;
t.b=rc.b; if(rc.b==rc.len)t.b+=lc.b;
}
}
void pushdown(int x){
Node &t=pool[x];
if(t.tag!=-1){
pool[lch(x)].tag=t.tag;
pool[rch(x)].tag=t.tag;
t.tag=-1;
update(lch(x)); update(rch(x));
}
}
void build(int x,int l,int r){
Node &t=pool[x];
t.l=l; t.r=r; t.len=r-l+1; t.a=t.b=t.mx=t.len; t.tag=0;
if(l!=r){
int mid=(l+r)>>1;
build(lch(x),l,mid);
build(rch(x),mid+1,r);
}
}
void change(int x,int ql,int qr,int d){
Node &t=pool[x];
if(ql<=t.l && t.r<=qr){ t.tag=d; }
else{
int mid=(t.l+t.r)>>1;
pushdown(x);
if(ql<=mid) change(lch(x),ql,qr,d);
if(qr>mid) change(rch(x),ql,qr,d);
}
update(x);
}
void find(int x,int len){
Node &t=pool[x];
if(t.l==t.r){ change(1,t.l,t.r,1); return; }
pushdown(x);
Node &lc=pool[lch(x)], &rc=pool[rch(x)];
if(lc.mx>=len) find(lch(x),len);
else if(lc.b+rc.a>=len){
int tp=lc.r-lc.b+1;
change(1,tp,tp+len-1,1);
}
else find(rch(x),len);
}
int main(){
freopen("a.in","r",stdin);
scanf("%d%d",&n,&m);
build(1,1,n);
int a,b; char op[5];
for(int i=1;i<=m;i++){
scanf("%s",op);
if(op[0]=='A'){
scanf("%d",&a);
if(pool[1].mx<a) ans++;
else find(1,a);
}
else{
scanf("%d%d",&a,&b);
change(1,a,b,0);
}
}
printf("%d\n",ans);
}