BZOJ3226 [Sdoi2008]校門外的區間

BZOJ3226 [Sdoi2008]校門外的區間 線段樹

Description

抽象出5種運算維護集合S(S初始爲空)並最終輸出S

輸入 操作
U T S∪T
I T S∩T
D T S-T
C T T-S
S T S⊕T

基本集合運算如下:

輸入 操作
A∪B {x : xÎA or xÎB}
A∩B {x : xÎA and xÎB}
A-B {x : xÎA and xÏB}
A⊕B (A-B)∪(B-A)
Input

輸入共M行。
每行的格式爲X T,用一個空格隔開,X表示運算的種類,T爲一個區間(區間用(a,b), (a,b], [a,b), [a,b]表示)。

Output

共一行,即集合S,每個區間後面帶一個空格。若S爲空則輸出”empty set”。

Sample Input
U [1,5]
D [3,3]
S [2,4]
C (1,5)
I (2,3]
Sample Output
(2,3) 
HINT

對於 100% 的數據,0≤a≤b≤65535,1≤M≤70000

題解

可以發現,a,b,其實很小。而且這些集合的操作都是區間操作,就可以用線段樹來維護。因爲有開或閉區間,我們可以把a,b,放大2倍,相當與再x與x+1之間加一個x+0.5。這樣就可以很好地處理開,閉區間問題。
U :區間內更改爲1
I:區間外更改爲0
D:區間內更改爲0
C:區間外更改爲0,區間內取反
S:區間內取反
我這裏mark爲修改標記,rev爲取反標記。
再pushdown時注意一下順序。
本入代碼奇醜無比,不喜勿噴

#include <cstdio>
#include <iostream>
#include <cmath>
#include <stack>
#include <algorithm>
#include <cstring>
#include <climits>
#define MAXN 131070+10
#define LL long long
using namespace std;
bool num[MAXN<<2],ans[MAXN<<2];
int n=MAXN,m,mark[MAXN<<2],rev[MAXN<<2];
void build(int rt,int l,int r)
{   
    num[rt]=0;mark[rt]=-1;
    if(l==r) return ;
    build(rt<<1,l,l+r>>1);
    build(rt<<1|1,(l+r>>1)+1,r);
}
void pushdown(int rt,int l,int r)
{
    if(mark[rt]!=-1||rev[rt])
    {   
        if(l==r)
        {
            if(mark[rt]!=-1) num[rt]=mark[rt];
            if(rev[rt]) num[rt]^=rev[rt];
        }else
        {
            if(mark[rt]!=-1) 
            {
                mark[rt<<1]=mark[rt<<1|1]=mark[rt];
                rev[rt<<1]=rev[rt<<1|1]=0;
            }
            rev[rt<<1]^=rev[rt];rev[rt<<1|1]^=rev[rt];
        }
        rev[rt]=0;mark[rt]=-1;
    }
}
void update(int L,int R,int k,int l,int r,int rt)
{

    pushdown(rt,l,r);
    if(L<=l&&r<=R)
    {   
        if(k!=2) mark[rt]=k;
        else rev[rt]^=1;
        return ;
    }
    int m=(l+r)>>1;
    if(L<=m) update(L,R,k,l,m,rt<<1);
    if(R>m) update(L,R,k,m+1,r,rt<<1|1);
}
int query(int x,int l,int r,int rt)
{   
    pushdown(rt,l,r);
    if(l==r) return num[rt];
    int m=(l+r)>>1;
    if(x<=m) return query(x,l,m,rt<<1);
    if(x>m) return query(x,m+1,r,rt<<1|1);
}
int main()
{
    build(1,0,n);
    char k[4],l,r;int a,b;
    while(scanf("%s ",k)!=EOF)
    {
        scanf("%c",&l);
        scanf("%d,%d",&a,&b);
        scanf("%c",&r);
        if(l=='(') a=a*2+1; else a=a*2;
        if(r==')') b=b*2-1; else b=b*2;
        if(k[0]=='U') update(a,b,1,0,n,1);
        else if(k[0]=='I')  update(1,a-1,0,0,n,1),update(b+1,n,0,0,n,1);
        else if(k[0]=='D')  update(a,b,0,0,n,1);
        else if(k[0]=='C')  update(1,a-1,0,0,n,1),update(b+1,n,0,0,n,1),update(a,b,2,0,n,1);
        else if(k[0]=='S')  update(a,b,2,0,n,1);
    }
    int flag=0;
    for(int i=0;i<=n;i++)
    {
        ans[i]=query(i,0,n,1);
        if(!flag&&ans[i]==1) flag=1;
    }
    if(flag==0) {printf("empty set\n");return 0;}
    int be=-1,e=1;
    for(int i=0;i<=n+1;i++)
    {
        if(ans[i]==1) 
        {
            if(be==-1) be=i;
        }else
        {   
            if(ans[i-1]==1)
            {   
                e=i-1;
                if(be&1) printf("(%d,",be/2);
                else printf("[%d,",be/2);
                if(e&1) printf("%d) ",(e+1)/2);
                else printf("%d] ",e/2);
                be=-1;e=0;
            }
        }
    }
    printf("\n");
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章