bzoj 3226: [Sdoi2008]校门外的区间(线段树)

3226: [Sdoi2008]校门外的区间

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 874   Solved: 307
[ Submit][ Status][ Discuss]

Description

 
  受校门外的树这道经典问题的启发,A君根据基本的离散数学的知识,抽象出5种运算维护集合S(S初始为空)并最终输出S。现在,请你完成这道校门外的树之难度增强版——校门外的区间。
 
  5种运算如下:
U T
S∪T
I T
S∩T
D T
S-T
C T
T-S
S T
S⊕T
 
  基本集合运算如下:
A∪B
{x : xÎA or xÎB}
A∩B
{x : xÎA and xÎB}
A-B
{x : xÎA and xÏB}
A⊕B
(A-B)∪(B-A)
 

Input

  输入共M行。
  每行的格式为X T,用一个空格隔开,X表示运算的种类,T为一个区间(区间用(a,b), (a,b], [a,b), [a,b]表示)。
 

Output

 
  共一行,即集合S,每个区间后面带一个空格。若S为空则输出"empty set"。
 

Sample Input

U [1,5]
D [3,3]
S [2,4]
C (1,5)
I (2,3]

Sample Output

(2,3)

HINT

对于 100% 的数据,0≤a≤b≤65535,1≤M≤70000

Source

[ Submit][ Status][ Discuss]

题解:线段树。

因为有开闭区间之分,所以我们对于在每个数之间加一个点,让所有开区间的操作作用在中间点上。

五种集合操作

S∪T  直接在T区间打1标记。

S∩T   求并集,所以将T区间以外的区域清零即可

S-T  将T区间清零

T-S  将T区间以外的区域清零,在将T区间内的点取反即可。

S⊕T 这个操作就是除去S,T的并集,所以直接将T区间内的点取反即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 200003
using namespace std;
int n,m,tr[N*4],delta[N*4],rev[N*4],pos[N*2];
char s[100],cl,cr;
struct data
{
	int x,y,opt;
}a[N];
void solve(int now)
{
	rev[now]^=1;
	if (delta[now]&&rev[now])
	  rev[now]=0,delta[now]=(delta[now]==1?2:1);
	tr[now]=(tr[now]==1?0:1);
}
void pushdown(int now,int l,int r)
{
   if (delta[now]==1)
   {
     delta[now<<1]=delta[now<<1|1]=delta[now];
     rev[now<<1]=rev[now<<1|1]=0;
	 tr[now<<1]=tr[now<<1|1]=1;
	 delta[now]=0;	rev[now]=0;
   }
   else
    if (delta[now]==2)
	 {
	 	delta[now<<1]=delta[now<<1|1]=delta[now];
	 	rev[now<<1]=rev[now<<1|1]=0;
	 	tr[now<<1]=tr[now<<1|1]=0;
	 	delta[now]=0; rev[now]=0;
	 }	
   if (rev[now])
    {
    	solve(now<<1); solve(now<<1|1);
    	rev[now]=0;
	}
}
void update(int x)
{
	tr[x]=tr[x<<1]&&tr[x<<1|1];
}
void qjchange(int now,int l,int r,int ll,int rr,int v)
{
	if (ll>rr) return;
	if (ll<=l&&r<=rr)
	 {
	 	delta[now]=v; rev[now]=0;
	 	if (v==1) tr[now]=1;
	 	else tr[now]=0;
	 	return ;
	 }
	int mid=(l+r)/2;
	pushdown(now,l,r);
	if (ll<=mid)  qjchange(now<<1,l,mid,ll,rr,v);
	if (rr>mid) qjchange(now<<1|1,mid+1,r,ll,rr,v);
	update(now);
}
void reserve(int now,int l,int r,int ll,int rr)
{
	if (ll>rr) return;
	if (ll<=l&&r<=rr)
	 {
	 	rev[now]^=1;
	 	if (delta[now]&&rev[now])
	 	 rev[now]=0,delta[now]=(delta[now]==1?2:1);
	 	tr[now]=(tr[now]==1?0:1);
	 	return;
	 }
	int mid=(l+r)/2;
	pushdown(now,l,r);
	if (ll<=mid) reserve(now<<1,l,mid,ll,rr);
	if (rr>mid) reserve(now<<1|1,mid+1,r,ll,rr);
	update(now);
}
int find(int now,int l,int r,int x)
{
	if (l==r)  return tr[now];
	pushdown(now,l,r);
	int mid=(l+r)/2;
	if (x<=mid) return find(now<<1,l,mid,x);
	else return find(now<<1|1,mid+1,r,x);
}
int main()
{
	int x,y;
	while (scanf("%s %c%d,%d%c",s,&cl,&x,&y,&cr)!=EOF)
	  {
	  	n++;
	 	if (s[0]=='U')  a[n].opt=1;
	 	if (s[0]=='I')  a[n].opt=2;
	 	if (s[0]=='D')  a[n].opt=3;
	 	if (s[0]=='C')  a[n].opt=4;
	 	if (s[0]=='S')  a[n].opt=5;
	 	if (cl=='[')  a[n].x=2*x;
	 	else a[n].x=2*x+1;
	 	if (cr==']')  a[n].y=2*y;
	 	else  a[n].y=2*y-1;
	 	m=max(m,2*y);
	  }
	for (int i=1;i<=n;i++)
	 {
	 	if (a[i].opt==1)
	 	 qjchange(1,0,m,a[i].x,a[i].y,1);
	 	if (a[i].opt==2)
	 	 qjchange(1,0,m,0,a[i].x-1,2),qjchange(1,0,m,a[i].y+1,m,2);
	 	if (a[i].opt==3)
	 	 qjchange(1,0,m,a[i].x,a[i].y,2);
	 	if (a[i].opt==4)
	 	 qjchange(1,0,m,0,a[i].x-1,2),qjchange(1,0,m,a[i].y+1,m,2),
	 	 reserve(1,0,m,a[i].x,a[i].y);
	 	if (a[i].opt==5)
	 	 reserve(1,0,m,a[i].x,a[i].y);
	 }
	bool f=false;
	for (int i=0;i<=m;i++)
	{
	  pos[i]=find(1,0,m,i);
	  if (pos[i])  f=true;
    }
	int i=0; 
	while (i<=m)
	{
		while (pos[i]==0&&i<=m)  i++;
		if (pos[i]==0)  break;
		int j=i;
		while (pos[j]==1)  j++;
		j--;
		if (i%2==0)  printf("[%d,",i/2);
		else printf("(%d,",i/2);
		if (j%2==0)  printf("%d] ",j/2);
		else printf("%d) ",j/2+1);
		i=j+1;
	}
	if (!f)  printf("empty set\n");
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值