POJ-3225 Help with Intervals 线段树

        题目链接:http://poj.org/problem?id=3225

        题意:给你一些区间和操作,问你最后有哪些区间。

        很容易把操作化简,0,1表示是否包含区间,-1表示该区间内既有包含又有不包含

                               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互换

       直接覆盖比较简单,直接更新就好了。重要的是0/1互换,这里是一个异或操作,如果当前区间被完全覆盖,直接改变一下覆盖标记就可以了,否则改变异或标记,更新时向下传递。

       会发现端点不是很处理,这里参考了别人的方法,即每个坐标扩大2倍,奇数表示单位区间,偶数表示端点即可!

       My code:

//STATUS:C++_AC_954MS_2736KB 
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<vector>
#include<queue>
#include<math.h>
#include<map>
#include<set>
using namespace std;
#define LL __int64
#define pii pair<int,int>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int MAX=65536*2,INF=200000000;
const double esp=1e-6;
void update(int l,int r,int rt);
void query(int l,int r,int rt);
void pushdown(int rt);
int cover[MAX<<2],flag[MAX<<2],ans[MAX];
int a,b,c,n=MAX-1;
char op[2];
void work(int rt) {
	if (cover[rt] != -1) cover[rt] ^= 1;
	else flag[rt] ^= 1;
}
int main()
{
//	freopen("in.txt","r",stdin);
	int i,ta,tb,ok;
	char lc,rc;
	while(~scanf("%s %c%d,%d%c",op,&lc,&a,&b,&rc))
	{
		ta=(a<<1)+(lc=='(');
		tb=(b<<1)-(rc==')');
		if(op[0]=='U' || op[0]=='D'){
			c=(op[0]=='U');
			a=ta,b=tb;
			update(0,n,1);
		}
		if(op[0]=='I' || op[0]=='C'){
			c=0;
			b=ta-1,a=0;
			update(0,n,1);
			a=tb+1,b=n;
			update(0,n,1);
		}
		if(op[0]=='C' || op[0]=='S'){
			c=-1;
			a=ta,b=tb;
			update(0,n,1);
		}
	}	
	query(0,n,1);
	for(i=ok=0;i<=n;i++){
		if(ans[i]){
			ok++;
			for(a=i;ans[i+1];i++);
			b=i;
			lc=(a&1)?'(':'[';
			rc=(b&1)?')':']';
			a>>=1,b=(b+1)>>1;
			if(ok>1)putchar(' ');
			printf("%c%d,%d%c",lc,a,b,rc);
		}
	}
	if(!ok)printf("empty set");
	putchar('\n');
	return 0;
}

void pushdown(int rt)
{
	if(cover[rt]!=-1){
		cover[rt<<1]=cover[rt<<1|1]=cover[rt];
		flag[rt<<1]=flag[rt<<1|1]=0;
		cover[rt]=-1;	
	}
	if(flag[rt]){
		work(rt<<1);
		work(rt<<1|1);
		flag[rt]=0;
	}
}

void update(int l,int r,int rt)
{
	if(c>=0 && cover[rt]==c)return;
	if(a<=l && r<=b){
		if(c!=-1){
			cover[rt]=c;
			flag[rt]=0;
		}
		else if(cover[rt]!=-1){
			cover[rt]^=1;
			flag[rt]=0;
		}
		else 
			flag[rt]^=1;
		return;
	}
	pushdown(rt);
	int mid=(l+r)>>1;
	if(a<=mid)
		update(lson);
	if(b>mid)
		update(rson);
}

void query(int l,int r,int rt)
{
	if(!cover[rt])
		return;
	if(cover[rt]==1){
		int i;
		for(i=l;i<=r;i++)
			ans[i]=1;
		return;
	}
	pushdown(rt);
	int mid=(l+r)>>1;
	query(lson);
	query(rson);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值