【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
",t.cnt);
            sgt.update(1,1,100000,t.ml,t.mr,0);
            sgt.update(1,1,100000,l,r,i);
        }else{
            printf("%d
",sgt.query(1,1,100000,1,100000).cnt);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/gwj1314/p/10200103.html