BZOJ3226[Sdoi2008]校门外的区间 题解

题目大意:

有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)

思路:

每个数之间加入一个数,就像这样2 2.5 3 3.5 4 [2,3) -> [2,2.5] (3,4] -> [3.5,4] 用01表示集合,则U 区间涂1;I 两侧区间涂0;D 区间涂0;C 两侧涂0,中间取反;S 区间取反。用线段树解决,标记的下传很重要(被坑了)。

代码:

  1 #include<cstdio>
  2 #include<iostream>
  3 #define n 131073
  4 using namespace std;
  5
  6 int lazy[n<<2],num[n<<2],rev[n<<2];
  7
  8 int read()
  9 {
 10      int x=0,y=0;
 11      char ch=getchar();
 12      while (ch<‘0‘ || ch>‘9‘)
 13      {
 14            if (ch==‘(‘) y=1;
 15            ch=getchar();
 16      }
 17      while (ch>=‘0‘ && ch<=‘9‘)
 18      {
 19            x=x*10+ch-48;
 20            ch=getchar();
 21      }
 22      if (ch==‘)‘) y=-1;
 23      return x*2+y+2;
 24 }
 25
 26 void push_down(int x,int l,int r)
 27 {
 28      int y=lazy[x],z=rev[x];
 29      lazy[x]=-1,rev[x]=0;
 30      if (l==r)
 31      {
 32           if (y!=-1) num[x]=y;
 33           num[x]^=z;
 34           return;
 35      }
 36      if (y!=-1)
 37      {
 38          lazy[x<<1]=lazy[x<<1|1]=y;
 39          rev[x<<1]=rev[x<<1|1]=0;
 40      }
 41      rev[x<<1]^=z,rev[x<<1|1]^=z;
 42 }
 43
 44 void add(int L,int R,int l,int r,int cur,int val)
 45 {
 46      if (l>r) return;
 47      push_down(cur,L,R);
 48      if (l<=L && r>=R)
 49      {
 50            if (val<2) lazy[cur]=val;
 51            else rev[cur]^=1;
 52            return;
 53      }
 54      int mid=L+R>>1;
 55      if (l>mid) add(mid+1,R,l,r,cur<<1|1,val);
 56      else if (r<=mid) add(L,mid,l,r,cur<<1,val);
 57           else add(L,mid,l,mid,cur<<1,val),add(mid+1,R,mid+1,r,cur<<1|1,val);
 58 }
 59
 60 int ask(int l,int r,int x,int cur)
 61 {
 62     push_down(cur,l,r);
 63     if (l==r) return num[cur];
 64     int mid=l+r>>1;
 65     if (x<=mid) return ask(l,mid,x,cur<<1);
 66     else return ask(mid+1,r,x,cur<<1|1);
 67 }
 68
 69 int main()
 70 {
 71     char ch[9];
 72     for (int i=0;i<=n*4;i++) lazy[i]=-1;
 73     while (scanf("%s",ch)!=EOF)
 74     {
 75           int a=read(),b=read();
 76           if (ch[0]==‘U‘) add(1,n,a,b,1,1);
 77           if (ch[0]==‘I‘) add(1,n,1,a-1,1,0),add(1,n,b+1,n,1,0);
 78           if (ch[0]==‘D‘) add(1,n,a,b,1,0);
 79           if (ch[0]==‘C‘) add(1,n,1,a-1,1,0),add(1,n,a,b,1,2),add(1,n,b+1,n,1,0);
 80           if (ch[0]==‘S‘) add(1,n,a,b,1,2);
 81     }
 82     int h=0,t=0,flag=0;
 83     for (int i=1;i<=n;i++)
 84         if (ask(1,n,i,1))
 85         {
 86             if (!h) h=i;
 87             t=i;
 88         }
 89         else
 90         {
 91             if (h)
 92             {
 93                 if (flag) printf(" ");
 94                 else flag=1;
 95                 if (h&1) printf("(");
 96                 else printf("[");
 97                 printf("%d,%d",h/2-1,(t+1)/2-1);
 98                 if (t&1) printf(")");
 99                 else printf("]");
100             }
101             h=t=0;
102         }
103     if (!flag) printf("empty set");
104     else printf(" ");
105     return 0;
106 }
时间: 2024-10-15 04:07:54

BZOJ3226[Sdoi2008]校门外的区间 题解的相关文章

【分块】bzoj3226 [Sdoi2008]校门外的区间

题解见 : http://blog.csdn.net/iamzky/article/details/41088151 ORZ ZKY 2个懒标记:是否翻转,覆盖成了什么. 怎么处理一个块上有两个标记的情况呢? 若该块原来没有任何标记,或要打的标记和原本的标记种类相同,则直接打上标记: 若已有翻转标记,再覆盖时则先清除翻转标记,再打上覆盖标记: 若已有覆盖标记,再翻转时,则直接将覆盖标记取反. So 某个块上同时只会有1个标记. P.S.分块此题挺快的…… 1 #include<cstdio>

bzoj3226: [Sdoi2008]校门外的区间 线段树

题比较有趣,输入输出比较麻烦. 每个点拆成两个,线段树维护.(这题难点真的在输入输出) #include<bits/stdc++.h> #define N (1<<17) #define M (l+r>>1) #define P (k<<1) #define S (k<<1|1) #define K l,r,k #define L l,M,P #define R M+1,r,S #define Z int l=0,int r=N,int k=1

[SDOI2008]校门外的区间

Description [SDOI2008]校门外的区间 ### Solution 两个整数之间再建一个点(如\(1\)和\(2\)之间再建一个\(1.5\)这个点),然后把开区间变成\(\pm1.5\)的闭区间 如\((1,5)\)变成\([1.5,4.5]\) \(U\) 区间涂色 \(I\) 两侧区间涂\(0\) \(D\) 区间涂\(0\) \(C\) 两侧涂\(0\),中间取反 \(S\) 区间取反 Code 原文地址:https://www.cnblogs.com/Agakiss/p

BZOJ 3226 [SDOI2008]校门外的区间

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3226 题意: 给定一个空集合S,维护五种集合与集合的操作,将最终得到的集合输出. 对于集合S和T,操作包括S=S∪T.S=S∩T.S=S?T.S=T?S.S=S?T. 每次的操作是给定一个T,并保证T表示的元素是一段连续的区间,可能开可能闭,区间端点均为整数. 最终输出的集合S要按升序输出每个连续的区间. 操作数≤70000,集合的数字∈[0,65535]. 题解: 考虑到区间的端点均为整数

3226: [Sdoi2008]校门外的区间

链接 思路 bug漫天飞... 维护一颗线段树,支持区间赋值,和区间异或.因为会处理到一些方括号还是圆括号的问题,所以对于每一个下标都乘2,假设中间有一个.5即可,都变成了方括号,输出在处理一下. U  [l,r]赋值为1 I   [0,l-1],[r+1,n]赋值为0 D [l,r]区间涂0 C [0,l-1],[r+1,n]赋值为0,[l,r]区间异或 S [l,r]区间异或 bug列表:乘2后从0开始,因为0*2=0,0.5*2=1,zz的居然是从2开始的.. 读入的区间并不都是一位数..

Vijos1448校门外的树 题解

Vijos1448校门外的树 题解 描述: 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的…… 如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作: K=1,K=1,读入l.r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同 K=2,读入l,r表示询问l~r之间能见到多少种树 (l,r>0) 输入格式: 第一行n,m表示道路总长为n,共有m个操作 接下来m行为m个操作 输出格式: 对于每个k=2输出一个答案 样例输入:

[bzoj 3226]校门外的区间

题意 输出最后的集合   题解 校门外的树会做吧 区间知道是什么东西吧 校门外的区间会做了吧 昨天做个大线段树没做出来,今天做个小线段树压压惊 py一下输入数据,然后操作变成: U 区间涂1 I 两侧区间涂0 D 区间涂0 C 两侧涂0,中间取反 S 区间取反 #include<map> #include<stack> #include<queue> #include<cstdio> #include<string> #include<ve

洛谷P1047校门外的树题解

摘要: 此题是一个模拟题,但需要注意的一点就是它的树是从数轴的0开始,所以我们也要从0开始,这样才能实现代码. 代码: #include<iostream> using namespace std; int s[100000]; int main() { int l,m,x,y,d=0; cin>>l>>m; for(int i=0; i<=l; i++) s[i]=1; for(int i=0; i<m; i++) { cin>>x>&g

TyvjOJ题目 P1473 校门外的树3(线段树区间染色种类数不覆盖)

P1473 校门外的树3 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的-- 如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作: K=1,读入l,r表示在l~r之间种上的一种树 K=2,读入l,r表示询问l~r之间能见到多少种树 (l,r>0) 输入格式 第一行n,m表示道路总长为n,共有m个操作 接下来m行为m个操作 输出格式 对于每个k=