zoukankan      html  css  js  c++  java
  • BZOJ3226: [Sdoi2008]校门外的区间

    BZOJ3226: [Sdoi2008]校门外的区间

    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


    题解Here!
    很容易想到把区间转化成$01$序列来做。
    但是开闭区间怎么办?
    我们考虑这样一种变换:$[2,3)->[2,2.5],(3,4]->[2.5,4]$
    那么把所有区间这样处理之后,再乘$2$,就是我们要处理的整数区间。
    然后用线段树维护一下区间标记就好。
    操作一是区间全改为$1$。
    操作二是区间之外全改为$0$。
    操作三是区间全改为$0$。
    操作四是先将区间之外全改为$0$,然后将区间全部异或$1$。
    操作五是区间全部异或$1$。
    线段树乱搞搞事就好辣!
    输出也很好搞,记录头尾$start,last$就好辣!
    然后我调了一个下午,发现我这个沙茶把线段树的标记下传写错了。。。药丸。。。
    附代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define LSON rt<<1
    #define RSON rt<<1|1
    #define DATA(x) a[x].data
    #define SIGN(x) a[x].c
    #define REV(x) a[x].flag
    #define LSIDE(x) a[x].l
    #define RSIDE(x) a[x].r
    #define WIDTH(x) (RSIDE(x)-LSIDE(x)+1)
    #define MAXN 200010
    using namespace std;
    int n=(65536*2+1);
    struct Segment_Tree{
    	int data,c,flag;
    	int l,r;
    }a[MAXN<<2];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    inline void pushup(int rt){
    	DATA(rt)=DATA(LSON)+DATA(RSON);
    }
    inline void pushdown(int rt){
    	if(LSIDE(rt)==RSIDE(rt))return;
    	if(SIGN(rt)!=-1){
    		REV(LSON)=0;SIGN(LSON)=SIGN(rt);
    		DATA(LSON)=SIGN(rt)*WIDTH(LSON);
    		REV(RSON)=0;SIGN(RSON)=SIGN(rt);
    		DATA(RSON)=SIGN(rt)*WIDTH(RSON);
    		SIGN(rt)=-1;
    	}
    	if(REV(rt)){
    		REV(LSON)^=1;
    		DATA(LSON)=WIDTH(LSON)-DATA(LSON);
    		REV(RSON)^=1;
    		DATA(RSON)=WIDTH(RSON)-DATA(RSON);
    		REV(rt)=0;
    	}
    }
    void buildtree(int l,int r,int rt){
    	LSIDE(rt)=l;RSIDE(rt)=r;SIGN(rt)=-1;REV(rt)=0;
    	if(l==r){
    		DATA(rt)=0;
    		return;
    	}
    	int mid=l+r>>1;
    	buildtree(l,mid,LSON);
    	buildtree(mid+1,r,RSON);
    	pushup(rt);
    }
    void update_rev(int l,int r,int rt){
    	if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
    		REV(rt)^=1;
    		DATA(rt)=WIDTH(rt)-DATA(rt);
    		return;
    	}
    	pushdown(rt);
    	int mid=LSIDE(rt)+RSIDE(rt)>>1;
    	if(l<=mid)update_rev(l,r,LSON);
    	if(mid<r)update_rev(l,r,RSON);
    	pushup(rt);
    }
    void update_all(int l,int r,int c,int rt){
    	if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
    		SIGN(rt)=c;REV(rt)=0;
    		DATA(rt)=c*WIDTH(rt);
    		return;
    	}
    	pushdown(rt);
    	int mid=LSIDE(rt)+RSIDE(rt)>>1;
    	if(l<=mid)update_all(l,r,c,LSON);
    	if(mid<r)update_all(l,r,c,RSON);
    	pushup(rt);
    }
    int query(int l,int r,int rt){
    	int ans=0;
    	if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt);
    	pushdown(rt);
    	int mid=LSIDE(rt)+RSIDE(rt)>>1;
    	if(l<=mid)ans+=query(l,r,LSON);
    	if(mid<r)ans+=query(l,r,RSON);
    	return ans;
    }
    void work(){
    	int start=-1,last=-1;
    	bool flag=false;
    	for(int i=1;i<=n;i++){
    		if(query(i,i,1)){
    			if(start==-1)start=i;
    			last=i;
    		}
    		else{
    			if(start!=-1){
    				if(flag)printf(" ");
    				else flag=true;
    				if(start&1)printf("(");
    				else printf("[");
    				printf("%d,%d",start/2-1,(last+1)/2-1);
    				if(last&1)printf(")");
    				else printf("]");
    			}
    			start=last=-1;
    		}
    	}
    	if(!flag)printf("empty set
    ");
    }
    void init(){
    	char ch[2],left,right;
    	int l,r;
    	buildtree(1,n,1);
    	while(~scanf("%s",ch)){
    		left=getchar();
    		while(left!='('&&left!='[')left=getchar();
    		scanf("%d,%d",&l,&r);
    		l<<=1;r<<=1;
    		right=getchar();
    		if(left=='(')l++;
    		if(right==')')r--;
    		l+=2;r+=2;
    		switch(ch[0]){
    			case 'U':{
    				update_all(l,r,1,1);
    				break;
    			}
    			case 'I':{
    				update_all(1,l-1,0,1);update_all(r+1,n,0,1);
    				break;
    			}
    			case 'D':{
    				update_all(l,r,0,1);
    				break;
    			}
    			case 'C':{
    				update_all(1,l-1,0,1);update_all(r+1,n,0,1);update_rev(l,r,1);
    				break;
    			}
    			case 'S':{
    				update_rev(l,r,1);
    				break;
    			}
    		}
    	}
    }
    int main(){
    	init();
    	work();
        return 0;
    }
    
  • 相关阅读:
    准备 FRM 考试——方法、工具与教训
    930. 和相同的二元子数组 前缀和
    1906. 查询差绝对值的最小值 前缀和
    剑指 Offer 37. 序列化二叉树 二叉树 字符串
    815. 公交路线 BFS
    518. 零钱兑换 II dp 完全背包
    1049. 最后一块石头的重量 II dp
    5779. 装包裹的最小浪费空间 二分
    5778. 使二进制字符串字符交替的最少反转次数 字符串 滑动窗口
    474. 一和零 dp
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9501993.html
Copyright © 2011-2022 走看看