【解题报告】 ZOJ 3641 Information Sharing - 并查集+模拟

/*
	ZOJ 3641 Information Sharing 并查集+模拟
	题意:给出了一些人对应了几个数字(information)
	然后又有一些人会分享数字(share information)分享是双向的,取并集
	最后会问某些人在此刻拥有哪些数字(information he has gotten)
	做法:由于数字的个数才1000(at most 1000 distinct information)
	所以每个人用一个集合表示,每个人集合的大小不会很大,然后分享的操作就是
	并查集并的过程,而输出只需要直接输出集合的大小即可。

*/


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#define CLR(c,v) memset(c,v,sizeof(c))
using namespace std;
const int N = 1e5 + 5;

map <string ,int>list;
set<int > dset[N];
int father[N];
int n_people = 0;

int getid(string name){
	if(list.find(name) == list.end()){
		// 在这里初始化
		list[name] = ++n_people;
		father[n_people] = n_people;
		dset[n_people].clear();
	}
	return list[name];
}

int find(int x){
	if(x == father[x]) return x;
	return father[x] = find(father[x]);
}

void Union(int name1,int name2){
	int f1 = find(name1);
	int f2 = find(name2);
	if(f1 == f2)return;
	if(dset[f1].size() > dset[f2].size()){
		swap(f1,f2);
	}
	for(set <int >::iterator it = dset[f1].begin() ; it != dset[f1].end() ; it++){
		dset[f2].insert(*it);
	}
	father[f1] = f2;
}

int main(){
	//freopen("in.txt","r",stdin);
	int T;
	while(~scanf("%d",&T)){
		list.clear();
		n_people = 0;
		while(T--){
			string ins,name1;
			cin >> ins >> name1;
			int id1 = getid(name1);
			if(ins[0] == 'a'){
				int m;scanf("%d",&m);
				for(int i = 0; i < m ; i++){
					int a;scanf("%d",&a);
					dset[id1].insert(a);
				}
			}else if(ins[0] == 's'){
				string name2;
				cin >> name2;
				Union( id1 , getid(name2));
			}else{
				id1 = find(id1);
				cout << dset[id1].size() << endl;
			}
		}
	}
	return 0;
}

/*
这个是用了两个map的程序,TLE了。。。
后来看了看人家写的,发现转成int的就可以了。。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#define CLR(c,v) memset(c,v,sizeof(c))
using namespace std;
const int N = 1000 + 5;

map <string ,string>father;
map <string ,set<int > > sdmap;

void debug(){

}

string find(string& name){
	if(name == father[name]) return name;
	return father[name] = find(father[name]);
}

void Union(string& name1,string& name2){
	string f1 = find(name1);
	string f2 = find(name2);

	if(sdmap[f1].size() > sdmap[f2].size()){
		swap(f1,f2);
	}
	for(set <int >::iterator it = sdmap[f1].begin() ; it != sdmap[f1].end() ; it++){
		sdmap[f2].insert(*it);
	}
	father[f1] = f2;

}

int main(){
	//freopen("in.txt","r",stdin);
	int T;
	while(~scanf("%d",&T)){
		sdmap.clear();
		father.clear();
		while(T--){
			string ins;
			cin >> ins;
			if(ins[0] == 'a'){
				string name;int m;
				cin >> name >> m;
				father[name] = name;
				for(int i = 0; i < m ; i++){
					int a;scanf("%d",&a);
					sdmap[name].insert(a);
				}
			}else if(ins[0] == 's'){
				string name1,name2;
				cin >> name1 >> name2;
				Union(name1,name2);
			}else{
				string name;
				cin >> name;
				name = find(name);
				cout <<sdmap[name].size() << endl;
			}
		}
	}
	return 0;
}
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值