poj 3225 线段树+位运算

略复杂的一道题,首先要处理开闭区间问题,扩大两倍即可,注意输入最后要\n,初始化不能随便memset

采用线段树,对线段区间进行0,1标记表示该区间是否包含在s内
U T S ← S ∪ T 即将[l,r]标记为1
I T S ← S ∩ T 即将-oo~l和r~+oo标记为0,因为是并集,所以并集后的集合s一定在[l,r]内,则在l,r内的集合被标记是什么状态就是什么状态(表示是否属于s),[l,r]外的集合不属于s所以标记为0
D T S ← S - T  即将[l,r]标记为0,则在[l,r]内被s包含的集合也会标记为0表示不再属于s
C T S ← T - S  即先将-oo~l,r~+oo标记为0,这部分不属于[l,r]则一定不属于s,然后将[l,r]的标记0/1互换,因为属于s的不再属于s,不属于s的将属于s
S T S ← S ⊕ T  即属于s的不变,[l,r]中不属于s的(区间)0标记为1,属于s的(区间)1标记为0,所以[l,r]的标记0/1互换

最后对区间l,r标记时标记将l*2,r*2标记,如果是闭区间则对l*2+1,或r*2-1进行标记,则输出的时候只需判断奇偶就能判断开闭区间
是否覆盖0,1是否转换0,1的0,1转换都可以用异或去转换
Sample Input
U [1,5]
D [3,3]
S [2,4]
C (1,5)
I (2,3]
Sample Output
(2,3)

  1 #include<cstdio>

  2 #include<iostream>

  3 #include<algorithm>

  4 #include<cstring>

  5 #include<cmath>

  6 #include<queue>

  7 #define lson l,m,rt<<1

  8 #define rson m+1,r,rt<<1|1

  9 using namespace std;

 10 const int maxn=131072;

 11 int tot=0;

 12 int n,m,t;

 13 int Xor[maxn<<2],cov[maxn<<2];   //异或标记,覆盖标记

 14 int hash[maxn<<2];

 15 void XXor(int rt)

 16 {

 17     if(cov[rt]!=-1) cov[rt]^=1;     //说明该区域有值存在

 18     else Xor[rt]^=1;

 19 }

 20 void pushdown(int rt)

 21 {

 22     if(cov[rt]!=-1)

 23     {

 24         cov[rt<<1]=cov[rt<<1|1]=cov[rt];

 25         Xor[rt<<1]=Xor[rt<<1|1]=0;

 26         cov[rt]=-1;

 27     }

 28     if(Xor[rt])

 29     {

 30         XXor(rt<<1);

 31         XXor(rt<<1|1);

 32         Xor[rt]=0;

 33     }

 34 }

 35 void update(char op,int L,int R,int l,int r,int rt)

 36 {

 37     if(l>=L&&r<=R)

 38     {

 39 

 40         if(op=='U') cov[rt]=1,Xor[rt]=0;

 41         else if(op=='D')    cov[rt]=Xor[rt]=0;

 42         else if(op=='C'||op=='S')   XXor(rt);

 43         return;

 44     }

 45     pushdown(rt);

 46     int m=(l+r)>>1;

 47     if(L<=m) update(op,L,R,lson);

 48     else if(op=='I'||op=='C')   cov[rt<<1]=Xor[rt<<1]=0;

 49     if(m<R) update(op,L,R,rson);

 50     else if(op=='I'||op=='C')   cov[rt<<1|1]=Xor[rt<<1|1]=0;

 51 }

 52 void query(int l,int r,int rt)

 53 {

 54     if(cov[rt]==1)

 55     {

 56         for(int i=l;i<=r;i++)   hash[i]=1;

 57         return;

 58     }

 59     else if(cov[rt]==0) return;

 60     if(l==r)    return;

 61     pushdown(rt);

 62     int m=(r+l)>>1;

 63     query(lson);

 64     query(rson);

 65 }

 66 int main()

 67 {

 68     int i,j,k;

 69     //freopen("1.in","r",stdin);

 70     char l,r,op;

 71     int a,b;

 72     while(scanf("%c %c%d,%d%c\n",&op,&l,&a,&b,&r)!=EOF)

 73     {

 74         a<<=1,b<<=1;    //区间扩大一倍,解决开闭区间问题

 75         //printf("%d %d\n",a,b);

 76         if(l=='(')  a++;

 77         if(r==')')  b--;

 78         if(a>b)         //说明a和b的值相等

 79         {

 80             if(op=='C'||op=='I')    cov[1]=Xor[1]=0,printf("");    //整个区间为0

 81         }

 82         else    update(op,a,b,0,maxn,1);

 83     }

 84     k=0;

 85     query(0,maxn,1);    //此时区间内的有效区域值为1

 86     int s=-1,e;    //判断左右区间位置

 87 

 88     for(i=0;i<=maxn;i++)

 89     {

 90         if(hash[i]) //该区域被覆盖

 91         {

 92             if(s==-1)   s=i;

 93             e=i;

 94         }

 95         else

 96         {

 97             if(s!=-1)    //说明存在一个完整区间

 98             {

 99                 if(k++) printf(" ");

100                 printf("%c%d,%d%c",s&1?'(':'[',s>>1,(e+1)>>1,e&1?')':']');    //&运算用来判断奇偶,偶数的话二进制末位为0,and1得0,说明为闭区间

101                 s=-1;

102             }

103         }

104     }

105     if(k==0)    printf("empty set");

106     puts("");

107     return 0;

108 }

 

你可能感兴趣的:(poj)