【bzoj3226】[Sdoi2008]校门外的区间
2016-07-06 09:46
232 查看
Description
受校门外的树这道经典问题的启发,A君根据基本的离散数学的知识,抽象出5种运算维护集合S(S初始为空)并最终输出S。现在,请你完成这道校门外的树之难度增强版——校门外的区间。
5种运算如下:
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)
Input
输入共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
Source
线段树
那么我可以把(2,3]变成[2.5,3]
最后处理2.5就行了
为了方便,我们把整体乘二,最后讨论奇偶性来输出
并集是添加元素,输入[a,b]把a~b的元素赋值为1
交集是只能保留与输入范围重复的集合
输入范围重复代表输入范围以外全都要删去
则输入[a,b]就把1~a-1,b+1~65536全赋值为0
相减:A-B。则B中有的元素A中不能有
读入[a,b]则把a~b的元素全赋值为0
B-A。则A中有的元素B中不能有
则输入[a,b],把1~a-1,b+1~65536全赋值为0
再把a~b的元素取反
(A-B)∪(B-A)。
A-B是将1~a-1,b+1~65536的元素保留,B-A是将1~a-1,b+1~65536的元素清除,然后a~b的元素取反。
结合起来就是将a~b的元素取反。
如何用线段树实现
我们可在叶子节点存储是否有该元素,然后用col[]数组表示是否清零或添加
用rev[]数组表示是否取反
只在子节点存储0 1情况
代码:
受校门外的树这道经典问题的启发,A君根据基本的离散数学的知识,抽象出5种运算维护集合S(S初始为空)并最终输出S。现在,请你完成这道校门外的树之难度增强版——校门外的区间。
5种运算如下:
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)
Input
输入共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
Source
线段树
解题报告:
开闭区间取决于符号那么我可以把(2,3]变成[2.5,3]
最后处理2.5就行了
为了方便,我们把整体乘二,最后讨论奇偶性来输出
并集是添加元素,输入[a,b]把a~b的元素赋值为1
交集是只能保留与输入范围重复的集合
输入范围重复代表输入范围以外全都要删去
则输入[a,b]就把1~a-1,b+1~65536全赋值为0
相减:A-B。则B中有的元素A中不能有
读入[a,b]则把a~b的元素全赋值为0
B-A。则A中有的元素B中不能有
则输入[a,b],把1~a-1,b+1~65536全赋值为0
再把a~b的元素取反
(A-B)∪(B-A)。
A-B是将1~a-1,b+1~65536的元素保留,B-A是将1~a-1,b+1~65536的元素清除,然后a~b的元素取反。
结合起来就是将a~b的元素取反。
如何用线段树实现
我们可在叶子节点存储是否有该元素,然后用col[]数组表示是否清零或添加
用rev[]数组表示是否取反
只在子节点存储0 1情况
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #define M 65600 #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define n (M*2) //开成两倍大小 using namespace std; int col[n<<2],rev[n<<2],sum[n<<2];//范围也要改变 int read() { int x=0,f=0;char ch; ch=getchar(); while(ch<'0' || ch>'9'){if(ch=='(')f=-1; ch=getchar();} while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} if(ch==')')f=1; return x*2-f; } void build(int l,int r,int rt) { col[rt]=-1; rev[rt]=0; if(l==r){return;} int mid=(l+r)>>1; build(lson); build(rson); } void pushdown(int rt,bool fl,int l) { if(fl) { if(col[rt]!=-1)sum[rt]=col[rt]; sum[rt]^=rev[rt]; rev[rt]=0;col[rt]=-1; return;//return一定要有 } if(col[rt]!=-1) { col[rt<<1]=col[rt];col[rt<<1|1]=col[rt]; rev[rt<<1]=0;rev[rt<<1|1]=0; } rev[rt<<1]^=rev[rt]; rev[rt<<1|1]^=rev[rt]; rev[rt]=0;col[rt]=-1; } void update(int L,int R,int c,int l,int r,int rt) { if(R<L)return; pushdown(rt,(l==r),l); if(L<=l && R>=r) { if(c==-1)rev[rt]^=1; else col[rt]=c; return; } int mid=(l+r)>>1; if(L<=mid)update(L,R,c,lson); if(R>mid)update(L,R,c,rson); } int query(int c,int l,int r,int rt) { pushdown(rt,(l==r),l); if(l==r)return sum[rt]; int mid=(l+r)>>1; if(c<=mid)return query(c,lson); else return query(c,rson); } int main() { memset(col,-1,sizeof(col)); memset(sum,0,sizeof(sum)); memset(rev,0,sizeof(rev)); char ch1[50]; while(scanf("%s",ch1)!=EOF) { int a,b; a=read();b=read(); a+=2;b+=2; //cout<<ch1[0]<<" "<<a<<" "<<b<<endl; 4000 switch(ch1[0]) { case 'U':update(a,b,1,1,n,1);break; case 'I':update(1,a-1,0,1,n,1);update(b+1,n,0,1,n,1);break;//case一定要有break!!! case 'D':update(a,b,0,1,n,1);break; case 'C':update(1,a-1,0,1,n,1);update(b+1,n,0,1,n,1);update(a,b,-1,1,n,1);break; case 'S':update(a,b,-1,1,n,1);break; } } int l=-1,r=-1,flag=0; for(int i=1;i<=n;i++) { if(query(i,1,n,1)) { if(l==-1)l=i; r=i; } else { if(l!=-1) { if(flag==1)printf(" "); else flag=1; if(l&1)printf("("); else printf("["); printf("%d",l/2-1); printf(",%d",(r+1)/2-1);//通过数学方法可知 if(r&1)printf(")"); else printf("]"); l=-1;r=-1; } } } if(flag==0)printf("empty set"); return 0;//不能打回车 }