寒假刷题30:洛谷P2161 [SHOI2009]会场预约(线段树)

题目链接:

P2161 [SHOI2009]会场预约

题目解析:

听说是平衡树的题(然鹅我是在线段树树状数组分类里找到的它)
线段树做法:把题目看成一个仅实现区间修改的线段树,用tagtag数组打打标记即可
有空补一下平衡树树状数组做法吧…好像还有一个神奇的STL做法?
翻译:一定不咕一定不咕

AC代码(线段树):

#include<cstdio>
#define N 100200
#define ls i<<1
#define rs i<<1|1
int min(int a,int b) {return a>b?b:a;}
int max(int a,int b) {return a>b?a:b;}
struct data{
    int cnt,ml,mr,lc,rc;
    data operator + (const data &b) {return (data){(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;}
};
struct segmenttree{
    data tree[N<<3],tag[N<<3];
    void pushdown(int i)
    {
        if (!~tag[i].cnt) return;
        tree[ls].lc=tree[ls].rc=tree[rs].lc=tree[rs].rc=tag[i].cnt;
        if (tag[i].cnt)
        {
            tree[rs].cnt=tree[ls].cnt=1;
            tree[rs].ml=tree[ls].ml=tag[i].ml;
            tree[rs].mr=tree[ls].mr=tag[i].mr;
            tag[ls]=tag[rs]=tag[i];
        }
        else
        {
            int mid=(tag[i].ml+tag[i].mr)>>1;
            tree[rs].cnt=tree[ls].cnt=0;
            tree[ls].ml=tag[i].ml;
            tree[rs].ml=mid+1;
            tree[rs].mr=tag[i].mr;
            tree[ls].mr=mid;
            tag[ls]=tag[rs]=tag[i];
            tag[ls].mr=mid;tag[rs].ml=mid+1;
        }
        tag[i].clear();
    }
    void update(int i,int l,int r,int L,int R,int c)
    {
        if (L<=l&&r<=R)
        {
            tree[i].lc=tree[i].rc=c;
            tag[i].cnt=c;
            if (c)
            {
                tree[i].cnt=1;
                tree[i].ml=L;tree[i].mr=R;
                tag[i].ml=L;tag[i].mr=R;
            }
            else
            {
                tree[i].cnt=0;
                tree[i].ml=l;tree[i].mr=r;
                tag[i].ml=l;tag[i].mr=r;
            }
            return;
        }
        int mid=(l+r)>>1;
        pushdown(i);
        if (L<=mid) update(ls,l,mid,L,R,c);
        if (mid<R) update(rs,mid+1,r,L,R,c);
        tree[i]=tree[ls]+tree[rs];
    }
    data query(int i,int l,int r,int L,int R)
    {
        if (L<=l&&r<=R) return tree[i];
        pushdown(i);
        int mid=(l+r)>>1;
        if (mid<L) return query(rs,mid+1,r,L,R);
        if (mid>=R) return query(ls,l,mid,L,R);
        return query(ls,l,mid,L,mid)+query(rs,mid+1,r,mid+1,R);
    }
    void build(int i,int l,int r)
    {
        tag[i].clear();
        if (l==r)
        {
            tree[i].cnt=0;
            tree[i].lc=tree[i].rc=0;
            tree[i].ml=tree[i].mr=l;
            return;
        }
        int mid=(l+r)>>1;
        build(ls,l,mid);build(rs,mid+1,r);
        tree[i]=tree[ls]+tree[rs];
    }
}cof;
int main()
{
    int n,l,r;char a;
    scanf("%d",&n);
    cof.build(1,1,100000);
    while(n--)
    {
        while(a=getchar()) if (a=='A'||a=='B') break;
        if (a=='A')
        {
            scanf("%d%d",&l,&r);
            data tmp=cof.query(1,1,100000,l,r);
            printf("%d\n",tmp.cnt);
            cof.update(1,1,100000,tmp.ml,tmp.mr,0);
            cof.update(1,1,100000,l,r,n);
        }
        else
        {
            data tmp=cof.query(1,1,100000,1,100000);
            printf("%d\n",tmp.cnt);
        } 
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值