poj 3225 线段树之成段更新集合运算(交、并)
题目描述:
输入:
U [1,5]
D [3,3]
S [2,4]
C (1,5)
I (2,3]
输出:
(2,3)
解题思路:
题意很明显,主要就是为了完成集合当中的并、交、差以及异或运算。
仔细分析一下题目这五种运算:设T左右区间分别为l,r
U T |
将(l,r)当中的所有点都置为1 |
I T |
保留l,r中1的位置,将(-∞,l)(r,+ ∞)置为0 |
D T |
将(l,r)当中全部置为0 |
C T |
将(l,r)当中0,1互换,将(-∞,l)(r,+ ∞)置为0 |
S T |
将(l,r)当中0,1互换 |
至于开区间和闭区间的分别,可以用扩大总区间变为原来的两倍,用偶数来表示闭区间,基数来表示开区间。
其实这个线段树题,我觉得最难的还是在取反的过程当中,不过好好体会一下应该会很有收获的。
View Code
1 #include<iostream> 2 #include<stdio.h> 3 #define lson t<<1,l,m 4 #define rson t<<1|1,m+1,r 5 using namespace std; 6 const int N = 131071; 7 int cover[N<<2];//覆盖 8 int Re[N<<2];//Re reserve 反向 9 int hash[N<<2]; 10 void Dir_back(int t) 11 { 12 if(cover[t]!=-1)cover[t]^=1; 13 else Re[t]^=1; 14 } 15 void PushDown(int t) 16 { 17 if(cover[t]!=-1) 18 { 19 cover[t<<1]=cover[t<<1|1]=cover[t]; 20 Re[t<<1]=Re[t<<1|1]=0; 21 cover[t]=-1; 22 } 23 if(Re[t]) 24 { 25 Dir_back(t<<1); 26 Dir_back(t<<1|1); 27 Re[t]=0; 28 } 29 } 30 void update(int t,int l,int r,int L,int R,char o) 31 { 32 if(L<=l&&r<=R) 33 { 34 if(o=='U')cover[t]=1,Re[t]=0; 35 else 36 if(o=='D')cover[t]=0,Re[t]=0; 37 else 38 if(o=='C'||o=='S') 39 Dir_back(t); 40 return ; 41 } 42 PushDown(t); 43 int m=(l+r)>>1; 44 if(L<=m)update(lson,L,R,o); 45 else 46 { 47 if(o=='I'||o=='C') 48 cover[t<<1]=Re[t<<1]=0; 49 } 50 if(R>m)update(rson,L,R,o); 51 else 52 { 53 if(o=='I'||o=='C') 54 cover[t<<1|1]=Re[t<<1|1]=0; 55 } 56 } 57 void query(int t,int l,int r) 58 { 59 if(cover[t]==1) 60 { 61 for(int i=l;i<=r;i++) 62 hash[i]=1; 63 return ; 64 } 65 else 66 if(cover[t]==0)return ; 67 if(l==r)return ; 68 PushDown(t); 69 int m=(l+r)>>1; 70 query(lson); 71 query(rson); 72 } 73 int main() 74 { 75 char o,l,r; 76 int a,b; 77 while(~scanf("%c %c%d,%d%c",&o,&l,&a,&b,&r)) 78 { 79 getchar(); 80 a<<=1,b<<=1; 81 if(l=='(')a++; 82 if(r==')')b--; 83 if(a>b) 84 { 85 if(o=='I'||o=='C') 86 { 87 cover[1]=Re[1]=0; 88 } 89 } 90 else 91 update(1,0,N,a,b,o); 92 } 93 query(1,0,N); 94 int s=-1,e,flag=0; 95 for(int i=0;i<=N;i++) 96 { 97 if(hash[i]) 98 { 99 if(s==-1)s=i; 100 e=i; 101 } 102 else 103 { 104 if(s!=-1) 105 { 106 if(flag)printf(" "); 107 flag=1; 108 printf("%c%d,%d%c",s&1?'(':'[',s>>1,(e+1)>>1,e&1?')':']'); 109 s=-1; 110 } 111 } 112 } 113 if(!flag)printf("empty set\n"); 114 return 0; 115 }