题解: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 r−0.5)
乘2就可以换算成整数区间
问题二:数据结构
假定数据随机,
出题者确实没有卡,那么区间的个数不会很多,好像链表模拟也可以过
然后是odt模板
问题三:各种操作
- U U U:取出一段区间,赋值为 t r u e true true
- I I I :将 [ − 1 e 9 [-1e9 [−1e9, l − 1 ] l-1] l−1] 和 [ 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] [l,r] 赋值为 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;
}