题目链接:http://poj.org/problem?id=3225
题意描述:给你一个集合初始化为空集,然后让它和其他集合进行一系列操作,最后输出操作之后的集合,集合操作有U表示求并集,I表示求交集,D表示S与给出集合求差集,C表示给出集合与S的集合求差集,这里的区间有开有并
分析:假设不考虑区间的开与闭,用线段树来维护所有区间初始化为0
如果是U的话则将(l,r)的值赋值为1
如果是I的话则将(0,l-1)和(r+1,max)的值赋值为1
如果是D的话则将(l,r)赋值为0
如果是C的话则将(0,l-1)(r+1,max)的值赋值为0,将区间(l,r)的区间取反
如果是S的话则将(l,r)区间取反
但是这样都是建立在点树的基础上的,但这里单位区间和点都应该看成点,这里就需要一个转换左闭区间转换为点2*l,将左开区间转换为2*r+1,将右闭区间转换为2*r,将右开区间转换为2*r-1,那么这样之后所有的单位区间为一个点,点也是一个点,这样就可以用线段树来维护啦,具体见代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=65535*2;
struct node
{
int l,r;
int tag;
int num;
}tree[N*4];
bool vis[N];
void bulid (int rt, int l , int r)
{
tree[rt].l=l;
tree[rt].r=r;
tree[rt].tag=0;
tree[rt].num=0;
if(l==r)return;
int mid=(l+r)>>1;
bulid(2*rt,l,mid);
bulid(2*rt+1,mid+1,r);
}
void pushdown(int rt)
{
if(tree[rt].tag!=-1)
{
tree[2*rt].tag=tree[rt].tag;
tree[2*rt+1].tag=tree[rt].tag;
tree[rt].tag=-1;
tree[2*rt].num=tree[2*rt+1].num=tree[rt].num=0;
}
if(tree[rt].num)
{
if(tree[2*rt].num)
tree[2*rt].num=0;
else if(tree[2*rt].tag!=-1) tree[2*rt].tag^=1;
else tree[2*rt].num=1;
if(tree[2*rt+1].num)tree[2*rt+1].num=0;
else if(tree[2*rt+1].tag!=-1) tree[2*rt+1].tag^=1;
else tree[2*rt+1].num=1;
tree[rt].num=0;
}
}
void insert(int rt, int l , int r, int op)
{
//if(tree[rt].l>l||tree[rt].r<r)return;
if(op<2)
{
if(tree[rt].l==l&&tree[rt].r==r)
{
tree[rt].tag=op;
tree[rt].num=0;
return;
}
}
else if(op==2)
{
if(l==tree[rt].l && r==tree[rt].r)
{
if(tree[rt].tag!=-1)
tree[rt].tag^=1;
else tree[rt].num^=1;
return;
}
}
int mid=(tree[rt].l+tree[rt].r)>>1;
pushdown(rt);
if(r<=mid)insert(2*rt,l,r,op);
else if(l>mid)insert(2*rt+1,l,r,op);
else {insert(2*rt,l,mid,op); insert(2*rt+1,mid+1,r,op);}
if(tree[2*rt].tag==tree[2*rt+1].tag)
tree[rt].tag=tree[2*rt].tag;
}
void quary(int rt)
{
if(tree[rt].l==tree[rt].r)
{
vis[tree[rt].l]=tree[rt].tag;
return;
}
pushdown(rt);
quary(2*rt);
quary(2*rt+1);
}
int main ()
{
char op, ch1, ch2;
int l,r,i,s;
bulid(1,0,N);
while(scanf("%c %c%d,%d%c",&op,&ch1,&l,&r,&ch2)!=EOF)
{
getchar();
l=l+l;
r=r+r;
if(ch1=='(')
l++;
if(ch2==')')
r--;
if(l>r)continue;
switch(op)
{
case 'U':
insert(1,l,r,1);break;
case 'I':
if(l>0)
insert(1,0,l-1,0);
if(r<N)
insert(1,r+1,N,0);break;
case 'D':
insert(1,l,r,0);break;
case 'C':
if(l>0)
insert(1,0,l-1,0);
if(r<N)
insert(1,r+1,N,0);
insert(1,l,r,2);break;
case 'S':
insert(1,l,r,2);break;
}
}
quary(1);
int begin, end, tmp = 1;
for(i = 0; i <= N; i++)
{
while(i <= N && !vis[i]) i++;
begin = i;
if(i > N) break;
while(i <= N && vis[i]) i++;
end = i - 1;
tmp = 0;
if(begin&1)
printf("(%d,", begin/2);
else
printf("[%d,", begin/2);
if(end&1)
printf("%d) ", (end+1)/2);
else
printf("%d] ", end/2);
}
if(tmp)
printf("empty set");
printf("\n");
return 0;
}