BZOJ3226 [Sdoi2008]校门外的区间
2017-04-13 15:30
309 查看
BZOJ3226 [Sdoi2008]校门外的区间 线段树
Description
抽象出5种运算维护集合S(S初始为空)并最终输出S输入 | 操作 |
---|---|
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) |
输入共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
题解
可以发现,a,b,其实很小。而且这些集合的操作都是区间操作,就可以用线段树来维护。因为有开或闭区间,我们可以把a,b,放大2倍,相当与再x与x+1之间加一个x+0.5。这样就可以很好地处理开,闭区间问题。U :区间内更改为1
I:区间外更改为0
D:区间内更改为0
C:区间外更改为0,区间内取反
S:区间内取反
我这里mark为修改标记,rev为取反标记。
再pushdown时注意一下顺序。
本入代码奇丑无比,不喜勿喷
#include <cstdio> #include <iostream> #include <cmath> #include <stack> #include <algorithm> #include <cstring> #include <climits> #define MAXN 131070+10 #define LL long long using namespace std; bool num[MAXN<<2],ans[MAXN<<2]; int n=MAXN,m,mark[MAXN<<2],rev[MAXN<<2]; void build(int rt,int l,int r) { num[rt]=0;mark[rt]=-1; if(l==r) return ; build(rt<<1,l,l+r>>1); build(rt<<1|1,(l+r>>1)+1,r); } void pushdown(int rt,int l,int r) { if(mark[rt]!=-1||rev[rt]) { if(l==r) { if(mark[rt]!=-1) num[rt]=mark[rt]; if(rev[rt]) num[rt]^=rev[rt]; }else { if(mark[rt]!=-1) { mark[rt<<1]=mark[rt<<1|1]=mark[rt]; rev[rt<<1]=rev[rt<<1|1]=0; } rev[rt<<1]^=rev[rt];rev[rt<<1|1]^=rev[rt]; } rev[rt]=0;mark[rt]=-1; } } void update(int L,int R,int k,int l,int r,int rt) { pushdown(rt,l,r); if(L<=l&&r<=R) { if(k!=2) mark[rt]=k; else rev[rt]^=1; return ; } int m=(l+r)>>1; if(L<=m) update(L,R,k,l,m,rt<<1); if(R>m) update(L,R,k,m+1,r,rt<<1|1); } int query(int x,int l,int r,int rt) { pushdown(rt,l,r); if(l==r) return num[rt]; int m=(l+r)>>1; if(x<=m) return query(x,l,m,rt<<1); if(x>m) return query(x,m+1,r,rt<<1|1); } int main() { build(1,0,n); char k[4],l,r;int a,b; while(scanf("%s ",k)!=EOF) { scanf("%c",&l); scanf("%d,%d",&a,&b); scanf("%c",&r); if(l=='(') a=a*2+1; else a=a*2; if(r==')') b=b*2-1; else b=b*2; if(k[0]=='U') update(a,b,1,0,n,1); else if(k[0]=='I') update(1,a-1,0,0,n,1),update(b+1,n,0,0,n,1); else if(k[0]=='D') update(a,b,0,0,n,1); else if(k[0]=='C') update(1,a-1,0,0,n,1),update(b+1,n,0,0,n,1),update(a,b,2,0,n,1); else if(k[0]=='S') update(a,b,2,0,n,1); } int flag=0; for(int i=0;i<=n;i++) { ans[i]=query(i,0,n,1); if(!flag&&ans[i]==1) flag=1; } if(flag==0) {printf("empty set\n");return 0;} int be=-1,e=1; for(int i=0;i<=n+1;i++) { if(ans[i]==1) { if(be==-1) be=i; }else { if(ans[i-1]==1) { e=i-1; if(be&1) printf("(%d,",be/2); else printf("[%d,",be/2); if(e&1) printf("%d) ",(e+1)/2); else printf("%d] ",e/2); be=-1;e=0; } } } printf("\n"); return 0; }
相关文章推荐
- BZOJ3226[Sdoi2008]校门外的区间 题解
- 「BZOJ3226」[SDOI2008] 校门外的区间(线段树好题)
- BZOJ3226: [Sdoi2008]校门外的区间
- BZOJ 3226: [Sdoi2008]校门外的区间
- bzoj 3226: [Sdoi2008]校门外的区间
- [线段树 标记] BZOJ 3226 [Sdoi2008]校门外的区间
- [bzoj3226][Sdoi2008]校门外的区间——线段树
- BZOJ-3226 [SDOI2008]校门外的区间
- 3226: [Sdoi2008]校门外的区间
- 3226: [Sdoi2008]校门外的区间 线段树
- 【BZOJ】【P3226】【Sdoi2008】【校门外的区间】【题解】【线段树】
- 【SDOI2008】【BZOJ3226】校门外的区间
- 【分块】bzoj3226 [Sdoi2008]校门外的区间
- 3226: [Sdoi2008]校门外的区间
- BZOJ 3226 [SDOI2008]校门外的区间
- 【bzoj3226】[Sdoi2008]校门外的区间
- bzoj 3226: [Sdoi2008]校门外的区间(线段树)
- bzoj 3226 [Sdoi2008]校门外的区间(线段树)
- 3226: [Sdoi2008]校门外的区间
- BZOJ 题目 3226: [Sdoi2008]校门外的区间(线段树区间交并差异或)