【SHOI2009】【BZOJ2028】会场预约(线段树染色)
problem
- 维护一个时间序列,支持2种操作。
- A、拒绝[l,r]原来的预约,并输出拒绝了多少个(每个预约是一个时间段)
B、输出当前有效的预约个数
solution
考虑点主要在:取消区间[l,r]内的预约,而该预约在[l,r]外的部分也被一并取消了。
- 线段树每个节点维护5个信息:区间内的预约个数cnt(答案本身)。区间内预约最早开始个数ml, 最晚结束个数mr(用于处理题目条件,取消预约在区间外的部分)。区间左端点颜色lc, 区间右端点颜色rc(用以区间合并时求解区间内预约个数,连接处的值)。
- 对于每一个预定操作,我们将这一段区间内的所有预约,最早是从什么时候开始的(记为ml) 以及 最晚在什么时候结束(记为mr),先把ml~mr区间染上0的颜色标记为没有设置预约(可能超出l,r),再把这一次预定的区间染成这一次预约的颜色。
codes
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
struct SegmentTree{
const static int maxn = (2e5+5);
#define lch p<<1
#define rch p<<1|1
struct node{
int cnt, ml, mr, lc, rc;
node operator + (const node &b){
return (node){(cnt&&b.cnt)?cnt+b.cnt-(rc&&(rc==b.lc)):cnt+b.cnt,min(ml,b.ml),max(mr,b.mr),lc,b.rc};
}
void clear(){ml=mr=lc=rc=cnt=-1;}
}sgt[maxn<<2], tag[maxn<<2];
//正常建树
void build(int p, int l, int r){
tag[p].clear();
if(l == r){
sgt[p].cnt = 0;
sgt[p].lc = sgt[p].rc = 0;
sgt[p].ml = sgt[p].mr = l;
return ;
}
int mid = l+r>>1;
build(lch,l,mid);
build(rch,mid+1,r);
sgt[p] = sgt[lch]+sgt[rch];
}
void pushdown(int p){
if(!~tag[p].cnt)return ;
sgt[lch].lc = sgt[lch].rc = tag[p].cnt;
sgt[rch].lc = sgt[rch].rc = tag[p].cnt;
if(tag[p].cnt){
sgt[lch].cnt = sgt[rch].cnt = 1;
sgt[lch].ml = sgt[rch].ml = tag[p].ml;
sgt[lch].mr = sgt[rch].mr = tag[p].mr;
tag[lch] = tag[rch] = tag[p];
}else{
int mid = (tag[p].ml+tag[p].mr)>>1;
sgt[lch].cnt = sgt[rch].cnt = 0;
sgt[lch].ml = tag[p].ml, sgt[rch].ml = mid+1;
sgt[lch].mr = mid, sgt[rch].mr = tag[p].mr;
tag[lch] = tag[rch] = tag[p];
tag[lch].mr = mid, tag[rch].ml = mid+1;
}
tag[p].clear();
}
//将区间[L,R]的颜色改为c.
void update(int p, int l, int r, int L, int R, int c){
if(L<=l && r<=R){
sgt[p].lc = sgt[p].rc = c;
tag[p].cnt = c;
if(c){
sgt[p].cnt = 1;
sgt[p].ml = L, sgt[p].mr = R;
tag[p].ml = L, tag[p].mr = R;
}else{
sgt[p].cnt = 0;
sgt[p].ml = l, sgt[p].mr = r;
tag[p].ml = l, tag[p].mr = r;
}
return ;
}
pushdown(p);
int mid = l+r>>1;
if(L<=mid)update(lch,l,mid,L,R,c);
if(R>mid)update(rch,mid+1,r,L,R,c);
sgt[p] = sgt[lch]+sgt[rch];
}
//查询[L,R]内这段区间的五个信息
node query(int p, int l, int r, int L, int R){
if(L<=l && r<=R)return sgt[p];
pushdown(p);
int mid = l+r>>1;
if(L>mid)return query(rch,mid+1,r,L,R);
if(R<=mid)return query(lch,l,mid,L,R);
return query(lch,l,mid,L,R)+query(rch,mid+1,r,L,R);
}
}sgt;
int main(){
int n; scanf("%d",&n);
sgt.build(1,1,100000);
for(int i = 1; i <= n; i++){
char op; cin>>op;
if(op == 'A'){
int l, r; scanf("%d%d",&l,&r);
SegmentTree::node t = sgt.query(1,1,100000,l,r);
printf("%d\n",t.cnt);
sgt.update(1,1,100000,t.ml,t.mr,0);
sgt.update(1,1,100000,l,r,i);
}else{
printf("%d\n",sgt.query(1,1,100000,1,100000).cnt);
}
}
return 0;
}