Problem Description
These days, you can do all sorts of things online. For example, you can use various websites to make virtual friends. For some people, growing their social network (their friends, their friends' friends, their friends' friends' friends,
and so on), has become an addictive hobby. Just as some people collect stamps, other people collect virtual friends.
Your task is to observe the interactions on such a website and keep track of the size of each person's network.
Assume that every friendship is mutual. If Fred is Barney's friend, then Barney is also Fred's friend.
Your task is to observe the interactions on such a website and keep track of the size of each person's network.
Assume that every friendship is mutual. If Fred is Barney's friend, then Barney is also Fred's friend.
Input
Input file contains multiple test cases.
The first line of each case indicates the number of test friendship nest.
each friendship nest begins with a line containing an integer F, the number of friendships formed in this frindship nest, which is no more than 100 000. Each of the following F lines contains the names of two people who have just become friends, separated by a space. A name is a string of 1 to 20 letters (uppercase or lowercase).
The first line of each case indicates the number of test friendship nest.
each friendship nest begins with a line containing an integer F, the number of friendships formed in this frindship nest, which is no more than 100 000. Each of the following F lines contains the names of two people who have just become friends, separated by a space. A name is a string of 1 to 20 letters (uppercase or lowercase).
Output
Whenever a friendship is formed, print a line containing one integer, the number of people in the social network of the two people who have just become friends.
Sample Input
1 3 Fred Barney Barney Betty Betty Wilma
Sample Output
2 3 4
/*
我觉得此题可以用map+并查集
此题很坑的地方就是
while(scanf("%d",&t)!=EOF)
{
}
*/
#include <iostream>
#include <cstdio>
#include <string>
#include <map>
using namespace std;
#define maxn 200008//10万对,最多20万人
int father[maxn];
int rank1[maxn];
int n;
map <string,int> coll;
void init()
{
for(int i=1;i<=2*n;i++)
{
father[i]=i;
}
}
int find(int x)
{
if(x==father[x])return x;
return father[x]=find(father[x]);
}
int Union(int a,int b)
{
int aa=find(a);
int bb=find(b);
rank1[bb]+=rank1[aa]+1;
father[aa]=bb;
return rank1[bb]+1;
}
int main()
{
int t;
while(scanf("%d",&t)!=EOF)
{
while(t--)
{
memset(rank1,0,sizeof(rank1));
scanf("%d",&n);
init();
coll.clear();
int id=1;
for(int i=1;i<=n;i++)
{
string a,b;
cin>>a>>b;
if(coll[a]&&coll[b])//未必就在同个集合
{
if(find(coll[a])==find(coll[b]))
{
printf("%d\n",rank1[find(coll[a])]+1);
}
else printf("%d\n",Union(coll[a],coll[b]));
}
else if(coll[a]&&!coll[b])
{
coll[b]=id++;
printf("%d\n",Union(coll[a],coll[b]));
}
else if(!coll[a]&&coll[b])
{
coll[a]=id++;
printf("%d\n",Union(coll[a],coll[b]));
}
else //两个都没有的话
{
if(a!=b)
{
coll[a]=id++;coll[b]=id++;
father[id-1]=id-2;
rank1[id-2]=1;
printf("%d\n",2);
}
else
{
coll[a]=id++;
rank1[id-1]=0;
printf("%d\n",1);
}
}
}
}
}
return 0;
}
/*
我觉得此题可以用map+并查集
好吧。我以为是我的没按秩合并出了问题。
还是1250MS。比没按秩合并的还慢50MS。。。
STL真心够慢
*/
#include <iostream>
#include <cstdio>
#include <string>
#include <map>
using namespace std;
#define maxn 200008//10万对,最多20万人
int father[maxn];
int rank2[maxn];
int rank1[maxn];
int n;
map <string,int> coll;
void init()
{
for(int i=1;i<=2*n;i++)
{
father[i]=i;
}
}
int find(int x)
{
if(x==father[x])return x;
return father[x]=find(father[x]);
}
int Union(int a,int b)
{
int aa=find(a);
int bb=find(b);
if(rank1[aa]>rank1[bb])
{
father[bb]=aa;
rank2[aa]+=rank2[bb]+1;
return rank2[aa]+1;
}
else if(rank1[aa]==rank1[bb])
{
father[bb]=aa;
rank1[aa]++;
rank2[aa]+=rank2[bb]+1;
return rank2[aa]+1;
}
else
{
father[aa]=bb;
rank2[bb]+=rank2[aa]+1;
return rank2[bb]+1;
}
}
int main()
{
int t;
while(scanf("%d",&t)!=EOF)
{
while(t--)
{
memset(rank2,0,sizeof(rank2));
memset(rank1,0,sizeof(rank1));
scanf("%d",&n);
init();
coll.clear();
int id=1;
for(int i=1;i<=n;i++)
{
string a,b;
cin>>a>>b;
if(coll[a]&&coll[b])//未必就在同个集合
{
if(find(coll[a])==find(coll[b]))
{
printf("%d\n",rank2[find(coll[a])]+1);
}
else printf("%d\n",Union(coll[a],coll[b]));
}
else if(coll[a]&&!coll[b])
{
coll[b]=id++;
printf("%d\n",Union(coll[a],coll[b]));
}
else if(!coll[a]&&coll[b])
{
coll[a]=id++;
printf("%d\n",Union(coll[a],coll[b]));
}
else //两个都没有的话
{
if(a!=b)
{
coll[a]=id++;coll[b]=id++;
father[id-1]=id-2;
rank2[id-2]=1;
printf("%d\n",2);
}
else
{
coll[a]=id++;
rank2[id-1]=0;
printf("%d\n",1);
}
}
}
}
}
return 0;
}
以上两种速度都慢。1200MS。接下来这种用字典树实现映射。200MS
/*
用map各种慢~
用链表实现字典树我还是很不熟悉
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 200008
int cnt,n;//这个就是单词的实际数目和最大数目
int father[maxn];
int rank1[maxn];
struct Node
{
Node * pr[53];
int id;
Node()
{
id=0;
for(int i=0;i<=52;i++)
{
pr[i]=NULL;
}
}
}*root;
int idx(char c)
{
if(c>='A'&&c<='Z')return c-'A';
else return c-'a'+26;
}
int insert(char *s)
{
int len=strlen(s);
Node * p=root;
for(int i=0;i<len;i++)
{
int u=idx(s[i]);
if(p->pr[u]==NULL)
{
p->pr[u]=new Node();
}
p=p->pr[u];
}
if(p->id==0)
{
p->id=cnt++;
}
return p->id;
}//目测成功实现了插入节点了。可以获得这个单词的编号了
void init()
{
for(int i=1;i<=2*n;i++)
{
father[i]=i;
}
}
int find(int x)
{
if(x==father[x])return x;
return father[x]=find(father[x]);
}
int Union(int a,int b)
{
int aa=find(a);
int bb=find(b);
father[aa]=bb;
rank1[bb]+=rank1[aa]+1;
return rank1[bb]+1;
}
void del(Node * p)
{
for(int i=0;i<52;i++)
{
if(p->pr[i])del(p->pr[i]);
}
delete p;
p=NULL;
}
int main()
{
int t;
while(scanf("%d",&t)!=EOF)
{
scanf("%d",&n);
memset(rank1,0,sizeof(rank1));
init();
root=new Node();
char str1[20],str2[20];
cnt=1;
for(int i=1;i<=n;i++)
{
scanf("%s%s",str1,str2);
int a=insert(str1);
int b=insert(str2);
if(find(a)!=find(b))
{
printf("%d\n",Union(a,b));
}
else
{
printf("%d\n",rank1[find(a)]+1);
}
}
del(root);
}
return 0;
}