Time Limit: 6000MS   Memory Limit: 131072K
Total Submissions: 12084   Accepted: 3033
Case Time Limit: 2000MS

Description

LogLoader, Inc. is a company specialized in providing products for analyzing logs. While Ikki is working on graduation design, he is also engaged in an internship at LogLoader. Among his tasks, one is to write a module for manipulating time intervals, which
have confused him a lot. Now he badly needs your help.

In discrete mathematics, you have studied several basic set operations, namely union, intersection, relative complementation and symmetric difference, which naturally apply to the specialization of sets as intervals.. For your quick reference they are summarized
in the table below:

Operation Notation

Definition

Union A ∪ B {x : x ∈ A or x ∈ B}
Intersection A ∩ B {x : x ∈ A and x ∈ B}
Relative complementation A − B {x : x ∈ A but x ∉ B}
Symmetric difference A ⊕ B (A − B) ∪ (B − A)

Ikki has abstracted the interval operations emerging from his job as a tiny programming language. He wants you to implement an interpreter for him. The language maintains a set S, which starts out empty and is modified as specified by the following
commands:

Command Semantics
U T S ← S ∪ T
I T S ← S ∩ T
D T S ← S − T
C T S ← T − S
S T S ← S ⊕ T

Input

The input contains exactly one test case, which consists of between 0 and 65,535 (inclusive) commands of the language. Each command occupies a single line and appears like

X T

where X is one of ‘U’, ‘I’, ‘D’, ‘C’ and ‘S’ and T is an interval in one of the forms (a,b)(a,b][a,b) and [a,b] (ab ∈ Z,
0 ≤ a ≤ b ≤ 65,535), which take their usual meanings. The commands are executed in the order they appear in the input.

End of file (EOF) indicates the end of input.

Output

Output the set S as it is after the last command is executed as the union of a minimal collection of disjoint intervals. The intervals should be printed on one line separated by single spaces and appear in increasing order of their endpoints. If S is
empty, just print “empty set” and nothing else.

Sample Input

U [1,5]
D [3,3]
S [2,4]
C (1,5)
I (2,3]

Sample Output

(2,3)

Source

【题解】

这题要用线段树来解。具体的解法:

U:因为是求并集。所以只要在原来S的基础上把(l,r)区间全部覆盖(置为1)就可以了。

I:求交集,X属于S,且X属于T,那只需要把除了(l,r)之外的所有区间都置为0就可以了。

D:X属于S,且X不属于T,则只要把(l,r)这个区间全部置为0就可以了。

C:X属于T,且X不属于S,这个有点麻烦,首先要把除了(l,r)的全部置为0,然后把(l,r)这段区间的0改为1,1改为0;这样才能满足要求;

S:其实S就是C+D的升级版。(X属于T且X不属于S)并上(X属于S且X不属于T),前者和C一样,然后后者和D一样,那么就只要进行C的后半部分操作就可以了。即只要把(l,r)这段区间的0改为1,1改为0就行了。

具体的做法:

【1】

一开始读入数据的时候,不管读入的区间a,b的括号是怎么样的。

都先乘上2

然后如果左括号是开区间

则a++;

如果右括号是开区间。

则b--;

最后输出区间的时候如果端点是奇数则是开区间;

然后对于左端点除2再输出即可,对于右端点则需要先加上1再除2.

【2】

设cover[rt]表示rt这个节点所代表的区间是否在集合中。

如果

cover[rt]==1,表示rt这个节点所代表的区间全部在集合中。

cover[rt] == 0,表示rt这个节点所代表的区间全部都不在集合中。

cover[rt]==-1,表示rt这个节点所代表的区间不能一概而论(有些可能在,有些可能不在)。

设XOR[rt]表示rt这个节点是否要进行异或操作。

【3】

当发现rt这个节点所代表的区间在所需要覆盖的区间范围内的时候。

先查看一下操作是什么。

如果是覆盖操作(即全部置为0或全部置为1),那么异或操作就没有意义了。

因为不管你之前怎么异或。我当前都只要把它改成一个特定的值了。

那么重新记录一下cover[rt]==需要覆盖的值。

然后XOR[rt]置为0,表示不需要再进行异或操作了。

然后如果是异或操作。

则需要看一下cover[rt]是不是-1,如果cover[rt]是-1,则说明这段区间没有被全部覆盖成相同的值。那么就只需要对XOR[rt]进行一下异或就行了。具体的如果XOR[rt]当前是1,就改为0,如果是0就改为1;

可以XOR[rt]^=1,又或者写成XOR[rt] = 1-XOR[rt];

然后如果cover[rt]不是-1,就说明这段区间被覆盖了相同的值。那么异或一下就可以了。

即cover[rt]^=1 (或者cover[rt]=1-cover[rt]);

然后直接退出当前的递归。

这些数据可以作为懒惰标记使用。

【4】

紧接着我们需要处理懒惰标记。

如果当前这个节点的cover值不为-1,就说明整个区间都会被覆盖成相同的值。那么这个时候异或标记是肯定为0的。因为如果cover标记存在,那么异或操作就不会对XOR数组进行操作了。这样的话,就只需要把两个儿子节点覆盖成和父亲节点一样的值就可以了。

然后把cover[rt]改为-1,表示下面已经不确定了。(因为如果访问了这个节点,我们可能就会对这个节点下面的部分进行修改了,不能够一概而论了。);

然后如果这个节点的cover值为-1,就看一下异或标记是否大于0,如果大于0;

则对儿子节点进行相同的判断(判断是否cover[儿子]为-1....);然后把异或标记置为0;

【5】

还有一个问题就是如何把区间外的部分置为0?

可以这样

在进行成段更新的时候

m=(begin+end)>>1;

正常情况下我们这样写

if ( l <= m)

updata(l,r,num,begin,end,rt<<1);

if (m <r)

updata(l,r,num,m+1,end,rt<<1|1);

我们这样写是为了不断地逼近有交集的那个部分。

但是

if (l >m)

则说明,我们索要求的l,r区间完全在左儿子所代表的区间的右边。

那么我们就可以在特定需要的情况下进行一个操作即

cover[rt<<1] == 0,XOR[rt<<1] =0;

这样就完成了对不在所操作的区间内的区间的覆盖0问题;右儿子也同理。所以代码就变成这样了。

int m = (begin + end) >> 1;

if (l <= m)

updata(op, l, r, begin, m, rt << 1);

else

if (op == 'I' || op == 'C')

cover[rt << 1] = XOR[rt << 1] = 0;

if (m < r)

updata(op, l, r, m + 1, end, rt << 1 | 1);

else

if (op == 'I' || op == 'C')

cover[rt << 1 | 1] = XOR[rt << 1 | 1] = 0;

具体的看代码注释

【代码】

#include <cstdio>
#include <cstring>
#define maxn 65535*2 +1 int cover[786420], XOR[786420]; //786420 = 65535*3*4
bool bo[maxn +10]; void push_down(int rt)
{
if (cover[rt] != -1) //如果这个节点整个被覆盖了某个值
{
cover[rt << 1] = cover[rt << 1 | 1] = cover[rt];//那么就把覆盖的值整个往儿子们传递。
XOR[rt << 1] = XOR[rt << 1 | 1] = 0;//因为覆盖了值。所以之前的异或标记也就没有意义了。直接置为0;
cover[rt] = -1;//之后可能会对这个节点所代表的区间进行操作。所以它不再是确定的了。
} else //如果被覆盖了某个值,那么就不可能有异或标记的所以这里写的是else
if (XOR[rt] > 0) //如果这个节点所代表的区间需要被异或。
{
if (cover[rt << 1] != -1)//如果左区间被完全覆盖了某个值
cover[rt << 1] ^= 1;//那么就把覆盖的值异或
else
XOR[rt<<1] ^= 1;//如果没有被完全覆盖,则把异或标记异或一下。
if (cover[rt << 1 | 1] != -1)//右区间同理。
cover[rt << 1 | 1] ^= 1;
else
XOR[rt << 1 | 1] ^= 1;
XOR[rt] = 0;//然后这个节点的异或标记重置一下。
}
} void updata(char op, int l, int r, int begin, int end, int rt) //操作符是op,当前节点rt所代表的区间是begin,end。然后
{//所要操作的区间是(l,r);
if (l <= begin && end <= r) //如果这个节点的区间整个被覆盖在所需要操作的区间内。
{
if (op == 'U')//如果是并集操作
{
cover[rt] = 1;//直接把这一段覆盖为1
XOR[rt] = 0;
}
else
if (op == 'D')//如果是D操作,则直接把这段区间覆盖为0.x属于S且x不属于T
{
cover[rt] = 0;
XOR[rt] = 0;
}
else
if (op == 'C' || op == 'S') //这是两个需要把操作区间整个异或的操作。
{
if (cover[rt] != -1)//如果这个区间之前已经被整个覆盖了值。
cover[rt] ^= 1;//那么就直接在覆盖值上异或一下就可以了。
else//如果之前没有覆盖值。
XOR[rt] ^= 1;//那么就在它的异或标记上进行操作。
}
return;//进行标记之后就不要往下走了。直接结束。
}
push_down(rt);//处理这个节点的懒惰标记。
int m = (begin + end) >> 1;//取得中点
if (l <= m)//忘左逼近那个交集区间。
updata(op, l, r, begin, m, rt << 1);
else
if (op == 'I' || op == 'C') //如果左儿子所代表的区间完全不在所求的区间内,则按照操作判断是否置0。
cover[rt << 1] = XOR[rt << 1] = 0;
if (m < r)//往右逼近交集区间
updata(op, l, r, m + 1, end, rt << 1 | 1);
else
if (op == 'I' || op == 'C') //右儿子同理。
cover[rt << 1 | 1] = XOR[rt << 1 | 1] = 0;
} void query(int l, int r, int rt)
{
if (cover[rt] == 1) //如果当前到的这个节点被完全覆盖了
{
for (int i = l; i <= r; i++)//就标记这个区间都在集合内。
bo[i] = true;
return;
}
else
if (cover[rt] == 0)//如果全部不覆盖则退出
return;//注意如果cover[rt]==-1,是不能退出的,还要往下找,找到能够一概而论的节点。
if (l == r) //如果左右断点都相同了则结束。
return;
push_down(rt);//处理懒惰标记什么的。
int m = (l + r) >> 1;
query(l, m, rt << 1);//往左往右递归。
query(m + 1, r, rt << 1 | 1);
} int main()
{
char op, l, r;//操作符 左括号 右括号
int a, b;
cover[1] = XOR[1] = 0; //一开始整个区间都覆盖着0
while (~scanf("%c %c%d,%d%c\n", &op, &l, &a, &b, &r)) //这个波浪号不能省略。不然会出错(不懂。。)
{
a = a << 1;b = b << 1;//先乘上2
if (l == '(')//如果左括号是开区间则加1,表示不能取到这个值。
a++;
if (r == ')')//右括号是开区间也同理,先减去1,注意我们已经先乘2了。
b--;
if (a > b) //如果右这种情况[a,b) ,a==b
{ //则所输入的集合是空集
if (op == 'I' || op == 'C') //因为这两种操作都是只有输入的集合里面的元素存在1,其他地方都是0.
cover[1] = XOR[1] = 0;//所以对于空集来说其他地方就都是0了。
}
else//如果满足a<=b,则是可以操作的
updata(op, a, b, 0, maxn, 1); //maxn就是输入的区间的端点范围*2+1;进行集合的操作即可。
}
memset(bo, false, sizeof(bo));//标记某个位置是否在集合内
query(0, maxn, 1);//进行询问。
int begin = -1, end;
bool haved = false;//haved用来判断是否要输出空格。。
for (int i = 0 ;i <= maxn;i++)//寻找到一个个的区间并输出
if (bo[i]) //如果这个点在集合内
{
if (begin == -1)//如果是起点就记录
begin = i;
end = i;
}
else
if (begin != -1)//如果遇到了一个不在集合内的点就判断是不是之前找到了连续的点组成了集合。
{
if (haved) printf(" ");//如果之前已经输出过答案了则要输出空格
haved = true;//记录已经找到一个集合了。
printf("%c%d,%d%c", begin & 1 ? '(' : '[', begin >> 1, (end + 1) >> 1, end & 1 ? ')' : ']');
begin = -1;//如果两端的端点某一个是奇数,则就是开区间,然后根据输入时的规则逆向想一下。然后除2就可以了。
}
if (!haved) //如果都没输出过集合。那就是空集了。
printf("empty set");
return 0;
}

【poj3225】Help with Intervals的更多相关文章

  1. 【LeetCode】435. Non-overlapping Intervals 解题报告(Python)

    [LeetCode]435. Non-overlapping Intervals 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemi ...

  2. 【LeetCode】56. Merge Intervals

    Merge Intervals Given a collection of intervals, merge all overlapping intervals. For example,Given  ...

  3. 【leetcode】435. Non-overlapping Intervals

    题目如下: Given a collection of intervals, find the minimum number of intervals you need to remove to ma ...

  4. 【LeetCode】56. Merge Intervals 解题报告(Python & C++ & Java)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  5. 【题解】 POJ 1201 Intervals(差分约束)

    懒得复制,戳我戳我 Solution: 这道题就是一个板子题 抽象成第\(a\)至第\(b\)间选择数的个数为\(c\),我们就可以用前缀和来表示,这样就可以得到不等式\(s[b]-s[a-1]> ...

  6. 【线段树】POJ3225-Help with Intervals

    ---恢复内容开始--- [题目大意] (直接引用ACM神犇概括,貌似是notonlysucess?) U:把区间[l,r]覆盖成1 I:把[-∞,l)(r,∞]覆盖成0 D:把区间[l,r]覆盖成0 ...

  7. 【目录】Leetcode

    Leetcode 1.动态规划 Palindrome Partitioning II(hard) ☆ Distinct Subsequences(hard) Edit Distance (hard) ...

  8. 【转】最短路&差分约束题集

    转自:http://blog.csdn.net/shahdza/article/details/7779273 最短路 [HDU] 1548 A strange lift基础最短路(或bfs)★254 ...

  9. 【转载】图论 500题——主要为hdu/poj/zoj

    转自——http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并 ...

随机推荐

  1. 读书笔记-Java设计模式

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! Java的封装性很好,拿访问控制符来讲,没有权限的类或方法是不能访问的.如public,都可访问:p ...

  2. 原生js大总结五

    041.在js中如何用方法将10进制的字符转换成16进制和8进制   数字.toString(16) 数字.toString(8)     042.如何创建时间对象   new Date()   04 ...

  3. 把java程序打包成.exe

    准备工作:将可执行的jar包跟资源跟第三方包都放到一个目录下. 能够将jre包也放入里面.这样在没有安装jre的情况下也能够执行. watermark/2/text/aHR0cDovL2Jsb2cuY ...

  4. 5.容器管理【Docker每天5分钟】

    原文:5.容器管理[Docker每天5分钟] Docker给PaaS世界带来的“降维打击”,其实是提供了一种非常便利的打包机制.该机制打包了应用运行所需要的整个操作系统,从而保证了本地环境和云端环境的 ...

  5. FTP中的授权规则

    在授权规则中,你可以管理自己的FTP站点以怎样的方式进行访问,比如每个进入站点的人都需要输入用户名密码.正则可以在授权规则中删除默认的配置“允许匿名用户读取”的规则. 也可以在此处,对不同的组或用户进 ...

  6. NPF

    NPF是一个协议驱动.从性能方面来看,这不是最好的选择,但是它合理地独立于MAC层并且有权使用原始通信 (raw traffic).NPF是Winpcap的核心部分,它是Winpcap完成困难工作的组 ...

  7. poj 2240 floyd算法

    Arbitrage Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 17349   Accepted: 7304 Descri ...

  8. volatile关键字深入理解

    前言: 这个关键字的重点就三个字,就是可见性.但是面试的时候,你说出可见性三个字,基本上满分100的话,最多只能得到20分.剩下的那80分,就要靠你用硬功夫去获得了. 所谓的硬功夫,其实就是要整明白, ...

  9. 中间件、服务器和Web服务器三者的区别

    相信很多的Web安全初学者和我一样,对中间件和服务器的认识不够深刻,对两者的概念可能会有所混淆. 正好今天在学习的时候突然想到了这个问题,粗略百度了一下,似乎网上对这个问题的解释不多,那么就由我来为大 ...

  10. IT从业人员关注哪些问题

    技术人员关注的问题非常多,但常见的至少有以下6种.特此整理,抓住核心问题,解决它. 一个人的精力和时间往往非常有限,能把核心问题都解决到位就是成功. 1.职业规划 大家从读小学开始,就是在为职业规划过 ...