SPOJ SETSTACK 题解

题意

有一个装着集合的栈,需要你实现以下操作:

  • PUSH. 将把空集 \(\{\}\) 推到堆栈上。
  • DUP. 将复制最顶层的集合(弹出堆栈,然后将该集合推入堆栈两次)。
  • UNION. 会弹出堆栈两次,然后将两个集合的联合值推入堆栈。
  • INTERSECT. 会弹出堆栈两次,然后将两个集合的交集推到堆栈上。
  • ADD. 会弹出堆栈两次,将第一个集合加入第二个集合,然后将得到的集合推到堆栈上。

对于每一次操作,输出操作后栈顶集合的大小,集合的大小为集合中元素的个数,嵌套的集合算一个,具体举个例子:

  • \(s = \{\{\{\{\{\}\}\}\},\, \{\{\}\}\}\)\(|s| = 2\)

思路

其实很简单,依题意模拟即可。

PUSH 和 DUP 比较简单,不讲。我们下面开始考虑如何进行其他三个操作:

  • ADD. 对于这个操作,我们将第一个集合取出来,然后用一个哈希表保存集合的唯一编号,将编号加入第二个集合即可。
  • INTERSECT. 注意不是 INTERSECTION !!!!!我因为这个交了整整一页,在这里对洛谷和 SPOJ 表示诚挚的歉意。废话不多说,我们考虑如何求这两个集合的交集。观察到 algorithm 库中有一个叫做 set_intersection 的函数,看起来可以求交集。的确可以,假设我们有三个集合 \(s_1,\,s_2,\,s_3\),我们要求 \(s_1 \cap s_2\) 的代码就是 set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), inserter(s3, s3.begin())); 很简单,对吧!
  • UNION. 再次观察到 algorithm 库中还有一个叫做 set_union 的函数,显然可以求并集。用法如下:set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), inserter(s3, s3.begin()));

对于每一次操作,很容易发现其实答案就是栈顶元素的 size,因为每一次有新的集合出现都会被压缩成一个数字,不会产生嵌套被多次统计的情况。

简单实现即可,注意千万不要打错 INTERSECT!!!!!!

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>
#include <set>
#include <vector>
#include <algorithm>
#include <stack>
#include <map>

#define int long long

using namespace std;

int t, n, cnt;
string s;
set<int> emp;
map<set<int>, int> mp;
stack<set<int>> stk;

void sign_up(set<int> st) {
if (!mp.count(st)) {
mp[st] = ++cnt;
}
}

signed main() {
cin >> t;
while (t--) {
cin >> n;
while (n--) {
cin >> s;
if (s == "PUSH") {
sign_up(emp);
stk.push(emp);
} else if (s == "DUP") {
set<int> s1 = stk.top();
stk.push(s1);
} else if (s == "UNION") {
set<int> s1, s2, s3;
s1 = stk.top();
stk.pop();
s2 = stk.top();
stk.pop();
set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), inserter(s3, s3.begin()));
sign_up(s3);
stk.push(s3);
} else if (s == "INTERSECT") {
set<int> s1, s2, s3;
s1 = stk.top();
stk.pop();
s2 = stk.top();
stk.pop();
set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), inserter(s3, s3.begin()));
sign_up(s3);
stk.push(s3);
} else if (s == "ADD") {
set<int> s1, s2;
s1 = stk.top();
stk.pop();
s2 = stk.top();
stk.pop();
s2.insert(mp[s1]);
sign_up(s2);
stk.push(s2);
}
cout << stk.top().size() << endl;
}
cout << "***\n";
}
}

SPOJ SETSTACK 题解
https://lixuannan.github.io/posts/51536
作者
CodingCow Lee
发布于
2024年6月12日
许可协议