poj 3225

线段树 求 区间 交,并,补。。

区间并:[L,R] 赋值为 1 即可

区间交:[0,L)  (R,MAXN]更新为 0

区间 S-T: [L,R]  更新为 0

区间 T-S:[0,L) (R,MAXN] 更新为 0,[L,R] 1 更新为 0,0更新为 1,即进行异或操作

区间对称差:[L,R] 1 更新为 0,0更新为 1.    (         对称差也可以定义为 (S并T)-(S交T)      )


接下来要处理 开区间和闭区间问题

可以这么做,将区间扩大两倍,即端点值 x2,对于 左 端点    偶数表示 闭区间 ,碰到 开区间就将 + 1 变成奇数

对于 右端点 ,偶数表示 闭区间, 碰到 开区间 就 - 1 变成奇数 


#include<iostream>
using namespace std;

#define lson u<<1
#define rson u<<1|1
#define MAXN 131100

bool visited[MAXN]={0};

struct Node{
	int lef,rig,XOR,COVER;//异或标记,覆盖标记
}T[MAXN<<2];

void Build(int u,int l,int r){
	T[u].lef=l;T[u].rig=r;
	T[u].COVER=T[u].XOR=0;
	if(l==r)return;
	int mid=(l+r)>>1;
	Build(lson,l,mid);Build(rson,mid+1,r);
}

void MakeXOR(int u){//进行异或时判断,如果有cover则转换状态,否则异或操作改变状态
	if(T[u].COVER!=-1)T[u].COVER^=1;
	else T[u].XOR^=1;
}

void PushDown(int u){
	if(T[u].COVER!=-1){
		T[lson].COVER=T[rson].COVER=T[u].COVER;
		T[lson].XOR=T[rson].XOR=0;//有cover时异或操作失效
		T[u].COVER=-1;
	}
	if(T[u].XOR){
		MakeXOR(lson);MakeXOR(rson);
		T[u].XOR=0;
	}
}

void Update(int u,int l,int r,char cmd){
	if(l<=T[u].lef&&T[u].rig<=r){
		if(cmd=='U'){T[u].COVER=1;T[u].XOR=0;}
		else if(cmd=='D'){T[u].COVER=T[u].XOR=0;}
		else if(cmd=='C'||cmd=='S')MakeXOR(u);
	}
	else {
		PushDown(u);
		if(l<=T[lson].rig)Update(lson,l,r,cmd);
		else if(cmd=='I'||cmd=='C')T[lson].COVER=T[lson].XOR=0;//左子树为空集
		if(r>=T[rson].lef)Update(rson,l,r,cmd);
		else if(cmd=='I'||cmd=='C')T[rson].COVER=T[rson].XOR=0;//右子树为空集
	}
}

void Query(int u){
	if(T[u].COVER==1){
		for(int i=T[u].lef;i<=T[u].rig;i++)visited[i]=true;return;
	}
	if(T[u].COVER==0||T[u].lef==T[u].rig)return;
	PushDown(u);
	Query(lson);Query(rson);
}

void GetAns(){
	bool flag=false;
	int ll=-1,rr=0;
	for(int i=0;i<=MAXN;i++){
		if(visited[i]==true){
			if(ll==-1)ll=i;
			rr=i;
		}
		else if(ll!=-1){
			if(flag)putchar(' ');flag=true;
			printf("%c%d,%d%c",ll&1?'(':'[',ll>>1,(rr+1)>>1,rr&1?')':']');
			ll=-1;
		}
	}
	if(!flag)printf("empty set");puts("");
}

int main(){
	char cmd;
	char bkl,bkr;//左括号,右括号
	int st,ed;//区间左端点,右端点
	Build(1,0,MAXN);//从0开始,因为区间端点可能为0
	while(scanf(" %c",&cmd)==1){
		scanf(" %c%d,%d%c",&bkl,&st,&ed,&bkr);
		st=(bkl=='('?(st<<1|1):st<<1);
		ed=(bkr==')'?(ed<<1)-1:ed<<1);
		if(st>ed){if(cmd=='I'||cmd=='C')T[1].COVER=T[1].XOR=0;}//空集
		else Update(1,st,ed,cmd);
	}
	Query(1);GetAns();
	return 0;
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值