题意:给出一个区间 0 - 65535。五种操作:
Operation | Notation | Definition |
---|---|---|
Union | A ∪ B | {x : x ∈ A or x ∈ B} |
Intersection | A ∩ B | {x : x ∈ A and x ∈ B} |
Relative complementation | A − B | {x : x ∈ A but x ∉ B} |
Symmetric difference | A ⊕ B | (A − B) ∪ (B − A) |
题解:说到底只有三种操作,将某区间全部置0,全部置1,全部取反。开区间与闭区间要注意区分,采用全部乘2的方式,是奇数则表明是‘(’,或者‘)’。偶数则是‘[',或者’]'。具体看代码。
#include<cstring>
#include<iostream>
using namespace std;
#define N 65535*2
#define L(u) (u<<1)
#define R(u) (u<<1|1)
int cnt;
struct RANGE
{
int l, r;
} ran[N+10];
struct NODE
{
int l, r, mid, v, change;
void operChange ()
{
/* 注意下面三个量的更新顺序, 当v!=-1时,保证change=0 */
if ( change ) change = 0; // 若原来记录需要改变,现在变成不要改变
else if ( v != -1 ) v ^= 1; // 若原来节点是纯色,且不要改变,现在将节点颜色取反
else change = 1; // 若原来不要改变,且不是纯色,则记录要改变
}
} node[4*N];
inline void updateDown ( int u )
{
if ( node[u].v != -1 )
{
node[L(u)].v = node[R(u)].v = node[u].v;
node[L(u)].change = node[R(u)].change = node[u].change = 0;
//node[u].v = -1; /* node[u]的子节点全部与node[u]的值相等,可以不向下跟新 */
}
if ( node[u].change )
{
node[L(u)].operChange ();
node[R(u)].operChange ();
node[u].change = 0;
}
}
inline void updateUp ( int u ) /* 注意向上更新的性质,若node[u].v!=-1,那么它的所有子节点的值都与node[u].v相等 */
{
if ( node[L(u)].v == node[R(u)].v )
node[u].v = node[L(u)].v;
else node[u].v = -1;
}
void build ( int u, int l, int r )
{
node[u].l = l;
node[u].r = r;
node[u].v = 0;
node[u].change = 0;
if ( l == r ) return;
node[u].mid = ( l + r ) >> 1;
build ( L(u), l, node[u].mid );
build ( R(u), node[u].mid+1, r );
}
void cover ( int u, int l, int r )
{
if ( l > node[u].r || r < node[u].l ) return;
if ( node[u].v == 1 ) return; // 节点已经为1,那么它的子节点一定为1
if ( node[u].l == l && node[u].r == r )
{
node[u].v = 1;
node[u].change = 0;
return;
}
updateDown(u);
if( r <= node[u].mid )
cover ( L(u), l, r );
else if ( l > node[u].mid )
cover ( R(u), l, r );
else
{
cover ( L(u), l, node[u].mid );
cover ( R(u), node[u].mid+1, r );
}
updateUp ( u );
}
void del ( int u, int l, int r )
{
if ( l > node[u].r || r < node[u].l ) return;
if ( node[u].v == 0 ) return; //节点已经为0,那么它的子节点一定为0
if ( node[u].l == l && node[u].r == r )
{
node[u].v = 0;
node[u].change = 0;
return;
}
updateDown(u);
if( r <= node[u].mid )
del ( L(u), l, r );
else if( l > node[u].mid )
del ( R(u), l, r );
else
{
del ( L(u), l, node[u].mid );
del ( R(u), node[u].mid+1, r );
}
updateUp ( u );
}
void negate ( int u, int l, int r )
{
if ( l > node[u].r || r < node[u].l ) return;
if ( node[u].l == l && node[u].r == r )
{
if ( node[u].v != -1 )
node[u].v ^= 1;
else node[u].change ^= 1;
return;
}
updateDown(u);
if ( r <= node[u].mid )
negate ( L(u), l, r );
else if ( l > node[u].mid )
negate ( R(u), l, r );
else
{
negate ( L(u), l, node[u].mid );
negate ( R(u), node[u].mid+1, r );
}
updateUp ( u );
}
void query ( int u )
{
if ( node[u].v == 1 )
{
cnt++;
ran[cnt].l = node[u].l;
ran[cnt].r = node[u].r;
return;
}
if ( node[u].v == 0 ) return;
if ( node[u].l == node[u].r ) return;
updateDown(u);
query ( L(u) );
query ( R(u) );
}
int main()
{
int l, r;
char oper, lch, rch;
build( 1, 0, N );
while ( scanf ("%c %c%d,%d%c%*c",&oper,&lch,&l,&r,&rch) != EOF )
{
l *= 2; if ( lch == '(' ) l++;
r *= 2; if ( rch == ')' ) r--;
switch ( oper )
{
case 'U':
cover ( 1, l, r ); break; // 并集
case 'I':
if ( l > 0 )
del ( 1, 0, l-1 ); // 交集
if ( r < N )
del ( 1, r+1, N ); break;
case 'D':
del ( 1, l, r ); break; // S - T
case 'C':
if ( l > 0 )
del ( 1, 0, l-1 ); // T - S
if ( r < N )
del ( 1, r+1, N );
negate ( 1, l, r ); break;
case 'S': // 对称差集
negate ( 1, l, r ); break;
default: break;;
}
}
cnt = 0;
query ( 1 );
if ( cnt == 0 )
{
printf("empty set\n");
return 0;
}
int s, e;
for ( int i = 1; i <= cnt; i++ )
{
s = -1;
if ( s == -1 ) s = ran[i].l;
while ( i <= cnt && ran[i].r == ran[i+1].l-1 ) i++;
if ( i > cnt ) i = cnt;
e = ran[i].r;
if ( s % 2 == 0 )
printf ( "[%d,", s / 2 );
else
printf ( "(%d,", s / 2 );
if ( e % 2 == 0 )
printf ( "%d] ", e / 2 );
else
printf ( "%d) ", (e+1) / 2 );
}
putchar('\n');
return 0;
}
写的精简一些如下,但是效率不如上面的
#include<cstring>
#include<iostream>
using namespace std;
#define N 65535*2
#define L(u) (u<<1)
#define R(u) (u<<1|1)
int array[N+3];
struct NODE
{
int l, r;
int cover;
int change;
void fun()
{
if ( change ) change = 0;
else if ( cover != -1 ) cover^=1;
else change=1;
}
} node[N*4];
void build ( int u, int l, int r )
{
node[u].l = l;
node[u].r = r;
node[u].cover=0;
node[u].change=0;
if ( l == r ) return;
int mid = ( l + r ) >> 1;
build ( L(u), l, mid );
build ( R(u), mid+1, r );
}
inline void updateDown ( int u )
{
if ( node[u].cover != -1 )
{
node[L(u)].cover = node[R(u)].cover = node[u].cover;
node[L(u)].change = node[R(u)].change = node[u].change = 0;
node[u].cover = -1;
}
if ( node[u].change )
{
node[L(u)].fun();
node[R(u)].fun();
node[u].change=0;
}
}
inline void updateUp ( int u )
{
if ( node[L(u)].cover == node[R(u)].cover )
node[u].cover = node[L(u)].cover;
else node[u].cover = -1;
}
void cover ( int u, int l, int r, int v )
{
if ( l > node[u].r || r < node[u].l )
return;
if ( l <= node[u].l && node[u].r <= r )
{
node[u].cover = v;
node[u].change = 0;
return;
}
updateDown ( u );
int mid = ( node[u].l + node[u].r ) >> 1;
if ( r <= mid )
cover ( L(u), l, r, v );
else if ( l > mid )
cover ( R(u), l, r, v );
else
{
cover ( L(u), l, mid, v );
cover ( R(u), mid+1, r, v );
}
updateUp ( u );
}
void negate ( int u, int l, int r )
{
if ( l > node[u].r || r < node[u].l )
return;
if ( l <= node[u].l && node[u].r <= r )
{
if ( node[u].cover != -1)
{
node[u].cover ^= 1;
return;
}
node[u].change ^= 1;
return;
}
updateDown ( u );
int mid = ( node[u].l + node[u].r ) >> 1;
if ( r <= mid )
negate ( L(u), l, r );
else if ( l > mid )
negate ( R(u), l, r );
else
{
negate ( L(u), l, r );
negate ( R(u), l, r );
}
updateUp ( u );
}
void query ( int u )
{
if ( node[u].l == node[u].r )
{
array[node[u].l] = node[u].cover;
return;
}
updateDown ( u );
query ( L(u) );
query ( R(u) );
}
int main()
{
int l, r;
char oper, lch, rch;
build ( 1, 0, N );
memset ( array, 0, sizeof(array) );
while(scanf("%c %c%d,%d%c%*c",&oper,&lch,&l,&r,&rch) != EOF )
{
l *= 2;
r *= 2;
if ( lch =='(' ) l++;
if ( rch ==')' ) r--;
switch ( oper )
{
case 'U':
cover ( 1, l, r, 1 );
break;
case 'I':
if ( l > 0 )
cover ( 1, 1, l-1, 0 );
if ( r < N )
cover ( 1, r+1, N, 0 );
break;
case 'D':
cover ( 1, l, r, 0 );
break;
case 'C':
if ( l > 0 )
cover ( 1, 0, l-1, 0);
if ( r < N )
cover ( 1, r+1, N, 0 );
negate ( 1, l, r );
break;
case 'S':
negate ( 1, l, r );
break;
default: break;;
}
}
query ( 1 );
int s, e, Empty = 1;
for ( int i = 0; i <= N; i++ )
{
while ( i <= N && !array[i] ) i++;
s = i;
if ( i > N ) break;
while ( i <= N && array[i] ) i++;
e = i-1;
Empty = 0;
if ( s % 2 == 0 )
printf ( "[%d,", s / 2 );
else
printf ( "(%d,", s / 2 );
if ( e % 2 == 0 )
printf ( "%d] ", e / 2 );
else
printf ( "%d) ", (e+1) / 2 );
}
if ( Empty )
printf("empty set");
putchar('\n');
return 0;
}