一间教室,起初是空的,有三种命令
1: "arrive Name m a1 a2 ..am" 名字为 Name的小朋友进来了,并且携带了m条信息,分别是a1,a2...am
2: "share Name1 Name2"
名字为Name1,Name2的小朋友分享他们的信息。
3: "check Name"
检查名字为Name的同学,并输出这个同学当前了解多少条不同的信息。
用map可以把名字hash成一个值,那么对每个小朋友可以用一个set来保存,合并的时候,名字之间的关系可以考虑用并查集存储,然后把set【A】的信息全部插入到set【B】中,那么一个集合里的人所了解的信息将会是同一个set。
两个注意的地方,
1:合并的时候可以直接循环一个set里的值,将其插入到父节点对应的set里,之后把这个集合清空,否则数据太大了会MLE..
2:由于存在share Name1 Name1,或者是这两个人当前已经在同一个集合里的情况,所以这里要判断一下,如果是同一个人或者是这两个人在同一个集合里,就continue掉。否则插入的时候自己往自己里面插元素等于没插,之后再一情况就错掉了= =...
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstring>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
const int maxn=201000;
int n,m,k;
int f[maxn];
string s,s1,s2,cmd;
int find(int x)
{
if (f[x]==x) return x;
else return f[x]=find(f[x]);
}
set<int>info[maxn];
set<int>::iterator it;
int ct;
int main()
{
// freopen("in.txt","r",stdin);
while(cin>>n)
{
memset(f,0,sizeof f);
ct=1;
map<string,int>hs;
hs.clear();
int id;
for (int i=1; i<=n; i++)
{
cin>>cmd;
if (cmd[0]=='a')
{
cin>>s;
if (hs.find(s)==hs.end())
{
id=ct;
info[id].clear();
f[ct]=ct;
hs[s]=ct++;
}
else id=hs[s];
cin>>m;
for (int i=0; i<m; i++)
{
cin>>k;
info[id].insert(k);
}
}
else if (cmd[0]=='s')
{
int id1,id2;
cin>>s1>>s2;
if (hs.find(s1)==hs.end())
{
id1=-1;
}
else id1=hs[s1];
if (hs.find(s2)==hs.end())
{
id2=-1;
}
else id2=hs[s2];
if (id1>=0 && id2>=0 && id1!=id2)
{
id2=find(id2);
id1=find(id1);
if (id1==id2) continue;
f[id2]=id1;
for (it=info[id2].begin(); it!=info[id2].end(); it++)
{
info[id1].insert(*(it));
}
info[id2].clear();
}
}
else if (cmd[0]=='c')
{
cin>>s;
if (hs.find(s)==hs.end()) cout<<0<<endl;
else
{
id=hs[s];
id=find(id);
cout<<info[id].size()<<endl;
}
}
}
}
return 0;
}