这个题是线段树经典题目,相信学过线段树的童鞋一定见过。。
我之前一直木有做,没仔细看,觉得应该不算太难,但是懒得做。。
前天一ACMer跟我聊线段树,谈到一种情况,就是线段和点同时有意义的时候,我当时就想,那扩大二倍应该就没啥问题了,然后他就说到这个题了。。。然后我决定做一下~
sha崽大牛线段树上面有这个题,可以把并交差与区间覆盖异或联系起来,引用下。具体地:
如果以1代表当前有值的话,那么假设T的区间为l,r,开闭先不管。。
U:把区间[l,r]覆盖成1
I:把[-∞,l)(r,∞]覆盖成0
D:把区间[l,r]覆盖成0
C:把[-∞,l)(r,∞]覆盖成0 , 且[l,r]区间0/1互换
S:[l,r]区间0/1互换
注意区间开闭的判断。
最后找连续的区间即可。
具体的我的代码有注释。。。难得我写一次注释。。嘿嘿。。代码很长。。。我觉得我缩不了了。。。><。。。
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define FOR(i,s,t) for(int i=(s); i<(t); i++)
#define BUG puts("here!!!")
#define STOP system("pause")
#define file_r(x) freopen(x, "r", stdin)
#define file_w(x) freopen(x, "w", stdout)
using namespace std;
const int MAX = 70000*2;
bool a[MAX<<2];
struct Tnode{ // 一维线段树
int l,r,cover;
bool x;
int len() { return r - l;}
int mid() { return MID(l,r);}
bool in(int ll,int rr) { return l >= ll && r <= rr; }
void lr(int ll,int rr){ l = ll; r = rr;}
};
Tnode node[MAX<<2];
void Build(int t,int l,int r)
{
node[t].x = false; // x 为 false 代表不异或
node[t].cover = 0; // cover为-1代表当前区间有0有1, 初始化为空集合
node[t].lr(l,r);
if( node[t].len() == 1 ) return ;
int mid = MID(l,r);
Build(L(t),l,mid);
Build(R(t),mid,r);
}
void Updata_x(int t) // 向下更新异或,因为cover在上一条命令结束时已经更新过了
{ // 保证异或标记为真,那么cover必然等于-1
if( node[t].len() == 1 )
{
if( node[t].x )
{
node[t].x = false;
node[t].cover = node[t].cover ^ 1;
}
return ;
}
if( node[t].cover != -1 )
{
node[L(t)].cover = node[R(t)].cover = node[t].cover;
node[L(t)].x = node[R(t)].x = false;
}
else
{
if( node[t].x )
{
node[L(t)].x = !node[L(t)].x;
node[R(t)].x = !node[R(t)].x;
if( node[L(t)].cover != -1 && node[L(t)].x )
{
node[L(t)].x = false;
node[L(t)].cover = node[L(t)].cover ^ 1;
}
if( node[R(t)].cover != -1 && node[R(t)].x )
{
node[R(t)].x = false;
node[R(t)].cover = node[R(t)].cover ^ 1;
}
node[t].x = false;
}
}
}
void Updata_cover(int t) // 更新父节点cover
{
if( node[L(t)].cover == node[R(t)].cover )
node[t].cover = node[L(t)].cover;
else
node[t].cover = -1;
}
void Updata(int t, int l, int r, int op, int val)
{
if( l >= r || l < 0 ) return ; // 防止出现一些非法状况
Updata_x(t);
if( node[t].in(l,r) )
{
if( op == 0 ) // 覆盖操作,把异或标记清空
{
node[t].cover = val;
node[t].x = 0;
}
else
{
if( node[t].cover != -1 )
node[t].cover = node[t].cover ^ 1; // 当前区间被覆盖,更改cover的值
else
node[t].x = !node[t].x; // 当前区间 有0有1
}
return ;
}
if( node[t].len() == 1 ) return ;
int mid = node[t].mid();
if( l < mid ) Updata(L(t), l, r, op, val);
if( r > mid ) Updata(R(t), l, r, op, val);
Updata_cover(t);
}
void Query(int t)
{
Updata_x(t);
if( node[t].len() == 1 )
{
a[ node[t].l ] = ( node[t].cover ? true : false );
return ;
}
Query(L(t));
Query(R(t));
}
void solve(char op, char l, char r, int x, int y)
{
int lb, lk, rb, rk, ll, rr;
lb = 2*x; lk = 2*x + 1; //左闭 左开
rb = 2*y + 1; rk = 2*y; //右闭 右开
ll = ( l == '(' ? lk : lb );
rr = ( r == ')' ? rk : rb );
switch( op )
{
case 'U':
Updata(1, ll, rr, 0, 1);
break;
case 'I':
Updata(1, 0, ll, 0, 0);
Updata(1, rr, MAX, 0, 0);
break;
case 'D':
Updata(1, ll, rr, 0, 0);
break;
case 'C':
Updata(1, ll, rr, 1, 0);
Updata(1, 0, ll, 0, 0);
Updata(1, rr, MAX, 0, 0);
break;
case 'S':
Updata(1, ll, rr, 1, 0);
}
}
void output()
{
int cnt = 0;
Query(1);
FOR(i, 0, MAX*2)
{
if( a[i] && cnt % 2 == 0 )
{
if( cnt != 0 )
printf(" ");
printf( i % 2 == 1 ? "(%d," : "[%d,", i/2);
cnt++;
}
if( !a[i] && cnt % 2 == 1 )
{
printf( i % 2 == 1 ? "%d]" : "%d)", i/2);
cnt++;
}
}
if( cnt == 0 )
printf("empty set");
printf("\n");
}
/*
左闭 2*x
左开 2*x + 1
右闭 2*y + 1
右开 2*y
*/
int main()
{
char op[5], s[100], l, r;
int x, y;
memset(a, false, sizeof(a));
Build(1, 0, MAX);
while( ~scanf("%s%s", op, s) )
{
sscanf(s, "%c%d,%d%c", &l, &x, &y, &r);
solve(op[0], l, r, x, y);
}
output();
return 0;
}