ZOJ 3641 Information Sharing

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3641

Information Sharing

Time Limit: 3 Seconds      Memory Limit: 65536 KB

There is going to be a test in the kindergarten. Since the kids would cry if they get a low score in the test, the teacher has already told every kid some information about the test in advance.
But the kids are not satisfied with the information teacher gave. They want to get more. On the testing day, some kids arrived to the classroom early enough, and then shared his/her information with another. kids are honest, if A shares with B, B can get all the information A knows, so does A.
At first the classroom is empty. As time pass by, a kid would arrive, or share information with other. However, the teacher hides somewhere, watching everything. She wants to know how much information some kid has gotten.

Input

There are multiple cases.
The first line of each case contains an integer n, indicating there is n actions.
The following n actions contain 3 types.
1: "arrive Name m a1 a2 ..am", means the kid called Name arrives at the classroom. He has m information, their id is a1 a2 ...am.
2: "share Name1 Name2", means that the kids called Name1 and Name2 share their information. (The sharing state will keep on, that means, if A share with B, later B share with C, A can also get all C's information via B. One kid may share with himself, but it doesn't mean anything.)
3: "check Name", means teacher wants to know the number of information kid called Name has got.

n is less than 100000, and is positive.The information id is among [0,1000000].
Each Name has at most 15 characters.
There would appears at most 1000 distinct information.
Each kid carry no more than 10 information when arriving(10 is included).

Output

For every "check" statement, output a single number.If there's no check statement, don't output anything.

Sample Input

8
arrive FatSheep 3 4 7 5
arrive riversouther 2 4 1
share FatSheep riversouther
check FatSheep
arrive delta 2 10 4
check delta
share delta FatSheep
check riversouther

Sample Output

4
2
5

Hint

check 1: FatSheep has 1 4 5 7, having all the information. So answer is 4.
check 2: delta has only 4 10 , doesn't have 1 5 7. So answer is 2
check 3: riversouther has 1 4 5 7 10, having all the information. So answer is 5

Author: LI, Chao
Contest: ZOJ Monthly, August 2012


大意——要考试了,老师给同学们讲了一些信息。但是同学们觉得这些不够,于是他们就相互交换意见,分享信息。现在给你n个操作,它们有3种形式:1.arrive Name m a1 a2 ... am代表名为Name的学生到达教室,他携带m个信息,分别是a1,a2,...,am。2.share Name1 Name2代表名为Name1和Name2的学生互相分享信息。3.check Name代表检查名为Name的学生当前携带的信息个数。要你对于每一个check操作都输出一个相对应的值。注意:如果A与B先分享了信息,而B与C后分享了信息,那么A也有C的信息。


思路——很显然,这是一个并查集的题。我们可以用set容器来存储学生的信息,并利用父亲集合来维护合并后的信息。开始时,我们初始化学生的父亲集合即为他自己。而在分享信息时,合并两个集合后改变它的父亲集合,并清空被改变父亲集合的集合。又因为询问的是学生名字,所以我们用map容器来映射学生所在的孩子集合。最后查找时只需找到该学生所在孩子集合的父亲集合,然后访问它的规模大小即可。


复杂度分析——时间复杂度:O(n+n*m),空间复杂度:O(n)


附上AC代码:


#include <iostream>
#include <cstdio>
#include <string>
#include <cmath>
#include <iomanip>
#include <ctime>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <deque>
//#pragma comment(linker, "/STACK:102400000, 102400000")
using namespace std;
typedef long long ll;
const double pi = acos(-1.0);
const double e = exp(1.0);
const double eps = 1e-8;
const int maxn = 100005;
set<int> mess[maxn]; // 存储学生携带的信息
map<string, int> test; // 存储学生携带的信息所在的集合
int father[maxn]; // 存储学生携带的信息所在的集合的父亲集合
char op[10], stu1[20], stu2[20]; // 分别表示选择的操作,学生1名字和学生2名字
int n; // 操作个数
short m; // 学生携带的信息个数

int find(int x); // 找到x集合的父亲集合
void _union(int x, int y); // 合并两个集合

int main(){
	ios::sync_with_stdio(false);
	while (~scanf("%d", &n)){
		for (int i=1; i<=n; i++){
			father[i] = i; // 初始化集合
			mess[i].clear(); // 清空集合里的信息
		}
		test.clear(); // 清空映射关系
		int cnt = 0; // 记录学生人数,也即按先后到达顺序编号
		while (n--){
			scanf("%s%s", op, stu1);
			if (!strcmp(op, "arrive")){
				scanf("%hd", &m);
				test[stu1] = ++cnt; // 映射关系编号
				int num;
				while (m--){
					scanf("%d", &num);
					mess[cnt].insert(num); // 该学生携带的信息放入集合
				}
			}
			else if (!strcmp(op, "share")){
				scanf("%s", stu2);
				_union(test[stu1], test[stu2]); // 合并学生1和学生2的信息
			}
			else
				printf("%d\n", mess[find(test[stu1])].size()); // 输出该学生所在父亲集合的信息个数
		}
	}
	return 0;
}

int find(int x){
	return father[x]==x ? x : father[x]=find(father[x]); // 路径压缩
}

void _union(int x, int y){
	x = find(x);
	y = find(y);
	if (x != y){ // 不在同一个集合,按规模大小合并
		if (mess[x].size() < mess[y].size()){
			mess[y].insert(mess[x].begin(), mess[x].end()); // y规模大,将x集合放到y集合中,并改变x的父亲集合以及清空集合x,以下类似
			father[x] = y; mess[x].clear();
		}
		else{
			mess[x].insert(mess[y].begin(), mess[y].end());
			father[y] = x; mess[y].clear();
		}
	}
}


你可能感兴趣的:(ZOJ,并查集)