题意:
求区间的交,并,补,对称差。。
思路:
为了表示开闭区间,用偶数表示闭区间端点,奇数表示开区间的。
[2,3) -> 4, 5
(3, 7) -> 7, 13
集合操作可以分解为两种,set和xor。。
先实现这两种操作,再讨论情况。。
const int Maxn = 65550*2;
#define lson(x) ((x)<<1)
#define rson(x) (((x)<<1)|1)
struct node {
int cover, x;
};
node a[Maxn*4+5];
void xor_helper(int o) {
if (a[o].cover == -1) {
a[o].x ^= 1;
} else {
a[o].cover ^= 1;
}
}
// 两种标记不会同时存在
void push_down(int o) {
int lc = lson(o), rc = rson(o);
if (a[o].cover != -1) {
a[lc].cover = a[rc].cover = a[o].cover;
a[lc].x = a[rc].x = 0;
a[o].cover = -1;
}
if (a[o].x) {
xor_helper(lc);xor_helper(rc);
a[o].x = 0;
}
}
void seg_update_cover(int L, int R, int o, int qL, int qR, int v) {
if (qL <= L && R <= qR) {
a[o].cover = v;
a[o].x = 0;
return;
}
push_down(o);
int lc = lson(o), rc = rson(o), mid = (L+R)>>1;
if (qL <= mid) seg_update_cover(L, mid, lc, qL, qR, v);
if (qR > mid) seg_update_cover(mid+1, R, rc, qL, qR, v);
}
void seg_update_xor(int L, int R, int o, int qL, int qR) {
if (qL <= L && R <= qR) {
xor_helper(o);return;
}
push_down(o);
int lc = lson(o), rc = rson(o), mid = (L+R)>>1;
if (qL <= mid) seg_update_xor(L, mid, lc, qL, qR);
if (qR > mid) seg_update_xor(mid+1, R, rc, qL, qR);
}
// query and mark
int mark[Maxn+5];
void seg_query(int L, int R, int o) {
if (a[o].cover == 1) {rep(i, L-1, R-1) mark[i] = 1;return;}
if (!a[o].cover) return;
push_down(o);
int lc = lson(o), rc = rson(o), mid = (L+R)>>1;
seg_query(L, mid, lc);seg_query(mid+1, R, rc);
}
void seg_build(int L, int R, int o) {
a[o] = (node) {0, 0};
if (L < R) {
int lc = lson(o), rc = rson(o), mid = (L+R)>>1;
seg_build(L, mid, lc);seg_build(mid+1, R, rc);
}
}
// debug
void seg_print(int L, int R, int o, int num) {
if (a[o].cover == 1) {printf("(%d %d)\n", L-1, R-1);return;}
if (a[o].cover == 0)return;
push_down(o);
int lc = lson(o), rc = rson(o), mid = (L+R)>>1;
seg_print(L, mid, lc, num+1);seg_print(mid+1, R, rc, num+1);
}
void ask() {
int n = Maxn;
memset(mark, 0, sizeof(mark));
seg_query(1, n, 1);
vector<pair<int, int> > ans;
int s = -1, e = -1;
for(int i=0;i<Maxn;++i) {
if (mark[i]) {
if (s == -1) s = i;
e = i;
} else {
if (s != -1) {
ans.push_back(make_pair(s, e));
s = -1;
}
}
}
if (ans.empty()) {printf("empty set\n");return;}
for (int i=0;i<ans.size();++i) {
int a = ans[i].first, b = ans[i].second;
char lhs = '[', rhs = ']';
if (ans[i].first & 1) {
lhs = '(';
--a;
}
if (ans[i].second & 1) {
rhs = ')';
++b;
}
printf("%c%d,%d%c", lhs, a/2, b/2, rhs);
printf("%c", i == ans.size()-1 ? '\n':' ');
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
#endif // ONLINE_JUDGE
char a, b, c;int x, y;
int n = Maxn;
seg_build(1, n, 1);
while (scanf("%c %c%d,%d%c\n", &a, &b, &x, &y, &c) != EOF) {
x *= 2;y *= 2;
if (b == '(') ++x;if (c == ')') --y;
x += 1;y += 1; // 因为最小为0,所以对应到线段树上的区间时+1
//printf("%c %d %d\n", a, x-1, y-1);
if (x > y) continue;
if (a == 'U') {
seg_update_cover(1, n, 1, x, y, 1);
} else if (a == 'I') {
if (x - 1 >= 1)
seg_update_cover(1, n, 1, 1, x-1, 0);
seg_update_cover(1, n, 1, y+1, Maxn, 0);
} else if (a == 'D') {
seg_update_cover(1, n, 1, x, y, 0);
} else if (a == 'C') {
if (x - 1 >= 1)
seg_update_cover(1, n, 1, 1, x-1, 0);
seg_update_cover(1, n, 1, y+1, Maxn, 0);
seg_update_xor(1, n, 1, x, y);
} else if (a == 'S') {
seg_update_xor(1, n, 1, x, y);
}
//seg_print(1, n, 1, 0);
//ask();
}
ask();
return 0;
}
本文详细介绍了如何使用线段树进行区间交并补运算,包括标记与更新操作,以及如何通过线段树实现对称差等集合操作。通过实例演示了线段树在解决区间问题时的高效性和灵活性。
&spm=1001.2101.3001.5002&articleId=45250533&d=1&t=3&u=a362bbb50f7346159e4432aa97e1651d)
1514

被折叠的 条评论
为什么被折叠?



