题意:给定一个集合S,S为空,然后对个集合进行操作,一共有四种操作方式,分别是:
交:表示,A区间和B区间将交处。
并:表示,A区间和B区间合起来。
差集(A - B):表示在区间A而不在区间B的区间。
对称差:表示(A - B)并(B - A),在A不在B中并上在B不在A中
通过一些列的操作之后,最后得到的区间是什么,然后顺序将其输出出来,如果是空集的话就输出empty set。
想法:首先这个是个典型的线段树的问题,并且是区更新。初始态的空集S相当于一串0000000。。。这串0相当长的。然后如果一个数位在区间中被包含,我们就用1表示,如果没有在区间中就还是0。
第一个需要解决的问题:关于开区间和闭区间的问题。这里采用一个非常巧妙地方法,也就是说将原先所为的整数1,2,3,4,5,...,n。若表示区间[4, 7],非常容易,4,5,6,7,但是要表示区间(4,7)这样子就非常麻烦了,反正都是整数有一种方法就是用[3,6]表示,但是这样一来,当操作到最后,我并不能有效的将输出结果区分为开区间和闭区间,显然是和题意不符合的。那么这个时候我采用将整个区间扩大的方法来表示开区间和闭区间。例如: [0, 0],(0, 1),[1, 1],(1, 2),[2, 2],(2, 3),[3, 3],...,(n-1, n),[n, n]。他们的标号是从0 ~ 2*n。其中奇数表示为点,也就是闭区间,偶数表示不包含整数点的区间,例如,如果要表示区间 (1,3],那么就是从(1,2)~ [3, 3]这里面的所有,也就是下标为1 * 2 + 1 ~ 3 * 2。此时就完美的将开区间和闭区间解决了,在输出的时候,例如,如果下表在3 ~ 6,那么由于3 % 2 = 1,表示是开区间,6 % 2 = 0,表示是闭区间那么他们所表示的数值分别是3 / 2 = 1,(6 + 1) / 2 = 3,不要问为啥,看着下标找规律的事情。此时,第一个问题就解决了。
第二个需要解决的问题:就是关于区间操作的问题:首先是 1.并:S <- S T,将T以内的变成1即可。2.交:S <- S T,将T以外的变成0,将T以内的不动。3.差:S <- S - T,将T以内的变为0;S <- T - S,将T以外变成0,T以内0,1交换。4.对称差:S <- S ⊕ T,将T中的0,1互换,这里理解非常容易,因为A ⊕ B = (A − B) ∪ (B − A)因为这里的(A − B)就相当于3中的第一个,(B − A)就相当于3中的第二个,第一个和第二个合并不就是将T中的0,1互换吗!!!
第三个需要解决的问题:这基本上就是属于代码的实现问题了,小细节挺多的,比如,数据中会出现区间为空集的情况,例如[3,2],(2,2)之类的,然后数组的大小要开到符合题意稍大一点就好。
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define L(x) x << 1
#define R(x) (x << 1) | 1
using namespace std;
const int INF = 65535 * 2 + 2;
bool hash[INF];
class CSegment_Tree
{
public:
CSegment_Tree(int node_num);
~CSegment_Tree()
{
delete[] segtree;
}
void PushDown(int cur_tnode);
void PushUp(int cur_tnode);
void Build(int cur_tnode, int lft, int rht);
void Updata_01(int cur_tnode, int pos_lft, int pos_rht, int val);
void Updata_xor(int cur_tnode, int pos_lft, int pos_rht);
void Query(int cur_tnode);
void fuc_xor(int cur_tnode);
private:
struct Tree_node
{
int seg_lft, seg_rht;
int ncol;
int nxor;
int mid()
{
return (seg_lft + seg_rht) >> 1;
}
};
struct Tree_node *segtree;
};
CSegment_Tree::CSegment_Tree(int num_node)
{
struct Tree_node *temp = new Tree_node[num_node * 4];
segtree = temp;
temp = NULL;
delete[] temp;
}
void CSegment_Tree::Build(int cur_tnode, int lft, int rht)
{
segtree[cur_tnode].seg_lft = lft;
segtree[cur_tnode].seg_rht = rht;
segtree[cur_tnode].ncol = 0;
segtree[cur_tnode].nxor = 0;
if(lft != rht)
{
int mid = segtree[cur_tnode].mid();
Build(L(cur_tnode), lft, mid);
Build(R(cur_tnode), mid + 1, rht);
}
}
void CSegment_Tree::Updata_01(int cur_tnode, int pos_lft, int pos_rht, int val)
{
if(pos_lft > pos_rht) return;
int lft = segtree[cur_tnode].seg_lft;
int rht = segtree[cur_tnode].seg_rht;
if(pos_lft <= lft && rht <= pos_rht)
{
segtree[cur_tnode].ncol = val;
segtree[cur_tnode].nxor = 0;
}
else
{
PushDown(cur_tnode);
int mid = segtree[cur_tnode].mid();
if(pos_lft <= mid) Updata_01(L(cur_tnode), pos_lft, pos_rht, val);
if(pos_rht > mid) Updata_01(R(cur_tnode), pos_lft, pos_rht, val);
PushUp(cur_tnode);
}
}
void CSegment_Tree::Updata_xor(int cur_tnode, int pos_lft, int pos_rht)
{
if(pos_lft > pos_rht) return;
int lft = segtree[cur_tnode].seg_lft;
int rht = segtree[cur_tnode].seg_rht;
if(pos_lft <= lft && rht <= pos_rht)
{
fuc_xor(cur_tnode);
}
else
{
PushDown(cur_tnode);
int mid = segtree[cur_tnode].mid();
if(pos_lft <= mid) Updata_xor(L(cur_tnode), pos_lft, pos_rht);
if(pos_rht > mid) Updata_xor(R(cur_tnode), pos_lft, pos_rht);
PushUp(cur_tnode);
}
}
void CSegment_Tree::Query(int cur_tnode)
{
if(segtree[cur_tnode].ncol == 1)
{
for(int i = segtree[cur_tnode].seg_lft; i <= segtree[cur_tnode].seg_rht; i++)
{
hash[i] = true;
}
return;
}
if(segtree[cur_tnode].ncol == 0) return;
PushDown(cur_tnode);
Query(L(cur_tnode));
Query(R(cur_tnode));
}
void CSegment_Tree::PushDown(int cur_tnode)
{
if(segtree[cur_tnode].ncol != -1)
{
segtree[L(cur_tnode)].ncol = segtree[R(cur_tnode)].ncol = segtree[cur_tnode].ncol;
segtree[L(cur_tnode)].nxor = segtree[R(cur_tnode)].nxor = 0;
}
if(segtree[cur_tnode].nxor)
{
segtree[cur_tnode].nxor = 0;
fuc_xor(L(cur_tnode));
fuc_xor(R(cur_tnode));
}
}
void CSegment_Tree::PushUp(int cur_tnode)
{
if(segtree[L(cur_tnode)].ncol == -1 || segtree[R(cur_tnode)].ncol == -1)
segtree[cur_tnode].ncol = -1;
else if(segtree[L(cur_tnode)].ncol == segtree[R(cur_tnode)].ncol)
segtree[cur_tnode].ncol = segtree[L(cur_tnode)].ncol;
else segtree[cur_tnode].ncol = -1;
}
void CSegment_Tree::fuc_xor(int cur_tnode)
{
if(segtree[cur_tnode].ncol != -1)
{
segtree[cur_tnode].ncol ^= 1;
segtree[cur_tnode].nxor = 0;
}
else segtree[cur_tnode].nxor ^= 1;
}
int main()
{
char op, L_flag, R_flag, key_return;
int lft, rht;
CSegment_Tree nseg(INF);
nseg.Build(1, 0, INF);
while(scanf("%c %c%d,%d%c%c", &op, &L_flag, &lft, &rht, &R_flag, &key_return) != EOF)
{
lft = lft * 2;
rht = rht * 2;
if(L_flag == '(') lft += 1;
if(R_flag == ')') rht -= 1;
switch(op)
{
case 'U':
nseg.Updata_01(1, lft, rht, 1);
break;
case 'I':
nseg.Updata_01(1, 0, lft - 1, 0);
nseg.Updata_01(1, rht + 1, INF, 0);
break;
case 'D':
nseg.Updata_01(1, lft, rht, 0);
break;
case 'C':
nseg.Updata_01(1, 0, lft - 1, 0);
nseg.Updata_01(1, rht + 1, INF, 0);
nseg.Updata_xor(1, lft, rht);
break;
case 'S':
nseg.Updata_xor(1, lft, rht);
break;
default:
break;
}
}
memset(hash, false, sizeof(hash));
nseg.Query(1);
int st = -1, ed;
bool find_ans = false;
for(int i = 0; i <= INF; i++)
{
if(hash[i] == true)
{
if(st == -1) st = i;
ed = i;
}
else if(st != -1)
{
if(find_ans) printf(" ");
find_ans = true;
printf("%c%d,%d%c", st % 2 == 1 ? '(' : '[', st / 2, (ed + 1) / 2, ed % 2 == 1 ? ')' : ']');
st = -1;
}
}
if(find_ans == false) printf("empty set");
printf("\n");
return 0;
}