题解:luogu P5568 [SDOI2008]校门外的区间

10 篇文章 0 订阅
2 篇文章 0 订阅

题解:luogu P5568 [SDOI2008]校门外的区间

luogu P5568 [SDOI2008]校门外的区间
前置知识:珂朵莉树

问题一:开闭区间

区间端点均为整数,不妨认为( l l l r r r)为( l + 0.5 l+0.5 l+0.5, r − 0.5 r-0.5 r0.5
乘2就可以换算成整数区间

问题二:数据结构

假定数据随机,出题者确实没有卡 ,那么区间的个数不会很多,好像链表模拟也可以过
然后是odt模板

问题三:各种操作

  • U U U:取出一段区间,赋值为 t r u e true true
  • I I I :将 [ − 1 e 9 [-1e9 [1e9 l − 1 ] l-1] l1] [ r + 1 [r+1 [r+1 1 e 9 ] 1e9] 1e9] 赋值为 f a l s e false false
  • D D D:将 [ l , r ] [l,r] [lr] 赋值为 f a l s e false false
  • C / S C/S C/S:暴力一些区间并取反

注意点

  • s e t set set的迭代器是 c o n s t const const的,如果想要修改,应该先删除后插入。
  • 删除节点之后要注意迭代器失效的问题
  • 合并两个相邻的区间
  • 好好写读入

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#define iter set<Node>::iterator
#define N 1000010
using namespace std;

struct Node {
	int l,r;bool f;
	inline bool operator < (const Node &o) const {
		return l<o.l;
	}
};

set<Node> odt;

iter split(int x) { //odt模板
	if(x>1e9) return odt.end();
	iter it=--odt.upper_bound((Node){x,0,0});
	if(it->l==x) return it;
	int l=it->l,r=it->r;bool f=it->f;
	odt.erase(it);
	odt.insert((Node){l,x-1,f});
	return odt.insert((Node){x,r,f}).first;
}

void assign(int l,int r,bool f) {
	iter itr=split(r+1),itl=split(l);
	odt.erase(itl,itr);
	odt.insert((Node){l,r,f});
}

char ch;bool fl;

bool getch() {
	while(ch!=EOF && ch!='U' && ch!='I' && ch!='D' && ch!='C' && ch!='S') ch=getchar();
	if(ch==EOF) return false;
	else return true;
}

bool read1() {
	while(ch!='(' && ch!='[') ch=getchar();
	if(ch=='(') return false;
	else return true;
}

bool read2() {
	while(ch!=')' && ch!=']') ch=getchar();
	if(ch==')') return false;
	else return true;
}

template<class T>
void read(T &x) {
	x=0;ch=getchar();bool f=false;
	for(;ch!='-' && !(ch>='0' && ch<='9');ch=getchar());
	if(ch=='-') ch=getchar(),f=true;
	for(;ch>='0' && ch<='9';ch=getchar()) x=x*10+ch-48;
	if(f) x=-x;
}

int main() {
//	freopen("interval.in","r",stdin);
//	freopen("interval.out","w",stdout);
	odt.insert((Node){(int)-1e9,(int)1e9,0}); //初始区间全部为空
	int l,r;
	while(getch()) {
		if(ch=='U') {
			fl=read1();
			read(l);
			if(fl) l=l*2; else l=l*2+1;
			read(r);
			fl=read2();
			if(fl) r=r*2; else r=r*2-1;
			if(l>r) continue;
			assign(l,r,true);
			continue;
		}
		if(ch=='I') {
			fl=read1();
			read(l);
			if(fl) l=l*2; else l=l*2+1;
			read(r);
			fl=read2();
			if(fl) r=r*2; else r=r*2-1;
			if(l>r) continue;
			assign(-1e9,l-1,false);
			assign(r+1,1e9,false);
			continue;
		}
		if(ch=='D') {
			fl=read1();
			read(l);
			if(fl) l=l*2; else l=l*2+1;
			read(r);
			fl=read2();
			if(fl) r=r*2; else r=r*2-1;
			if(l>r) continue;
			assign(l,r,false);
			continue;
		}
		if(ch=='C') {
			fl=read1();
			read(l);
			if(fl) l=l*2; else l=l*2+1;
			read(r);
			fl=read2();
			if(fl) r=r*2; else r=r*2-1;
			if(l>r) continue;
			iter itr=split(r+1),itl=split(l);
			for(;itl!=itr;++itl) {
				bool f=!itl->f;
				int L=itl->l,R=itl->r;
				odt.erase(itl);
				itl=odt.insert((Node){L,R,f}).first;   //先删除后插入,把新迭代器
			}										   //赋值给itl,防止迭代器失效
			assign(-1e9,l-1,false);
			assign(r+1,1e9,false);
			continue;
		}
		if(ch=='S') {
			fl=read1();
			read(l);
			if(fl) l=l*2; else l=l*2+1;
			read(r);
			fl=read2();
			if(fl) r=r*2; else r=r*2-1;
			if(l>r) continue;
			iter itr=split(r+1),itl=split(l);
			for(;itl!=itr;++itl) {
				bool f=!itl->f;
				int L=itl->l,R=itl->r;
				odt.erase(itl);
				itl=odt.insert((Node){L,R,f}).first;
			}
			continue;
		}
	}
	for(iter i=odt.begin();i!=odt.end();++i) {
		iter j=i;
		++j;
		if(j==odt.end()) break;
		if(i->r+1==j->l && i->f==j->f) {		//合并两个相邻区间
			iter itr=split(j->r+1),itl=split(i->l);
			odt.erase(itl,itr);
			i=odt.insert((Node){i->l,j->r,i->f}).first;
			--i;
		}
	}
	bool flag=true;
	for(iter i=odt.begin();i!=odt.end();++i) {
		if(i->f) {
			flag=false;break;
		}
	}
	if(flag) puts("empty set");
	else {
		for(iter itl=odt.begin();itl!=odt.end();++itl) if(itl->f) {
			if(itl->l&1) {
				putchar('(');
				printf("%d",itl->l/2);
				putchar(',');
			} else {
				putchar('[');
				printf("%d",itl->l/2);
				putchar(',');
			}
			if(itl->r&1) {
				printf("%d",(itl->r+1)>>1);
				putchar(')');
				putchar(' ');
			} else {
				printf("%d",itl->r/2);
				putchar(']');
				putchar(' ');
			}
		}
		putchar('\n');
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值