/*贡献出无数WA, 就因为一个地方写错, 悲剧的一晚上啊!不过能过了还是很爽的。
思路:用Trie树给字符串重新标号,然后用并查集,用一个a[i] 记录当前并查集跟结点上连接的结点数。*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct node
{
int flag;
node * next[53];
};
const int N = 200005;
int parent[N];
int rank[N];
int a[N];
int num;
node * newnode()
{
node *p = new node;
p->flag = 0;
for(int i = 0; i < 52; i++)
p->next[i] = NULL;
return p;
}
int insert(node *root, char *s)
{
node *p = root;
int i, len = strlen(s), t;
for(i = 0; i < len; i++)
{
if(isupper(s[i]))
t = s[i] - 'A';
else
t = s[i] - 'a' + 26;
if(p->next[t] == NULL)
p->next[t] = newnode();
p = p->next[t];
}
if(p->flag)
return p->flag;
else
{
p->flag = num++;
return p->flag;
}
}
void del(node *p)
{
if(p)
{
for(int i = 0; i < 52; i++)
if(p->next[i])
del(p->next[i]);
}
delete p;
p = NULL;
}
void init()
{
for(int i = 0; i < N; i++)
{
parent[i] = i;
a[i] = 1;
}
}
int find(int x)
{
int k = x, r = x, j;
while(r != parent[r])
r = parent[r];
while(k != r)
{
j = parent[k];
parent[k] = r;
k = j;
}
return r;
}
void union_set(int x, int y)
{
x = find(x);
y = find(y);
if(x == y) return ;
parent[x] = y;
a[y] += a[x];
}
int main()
{
//freopen("data.in", "r", stdin);
int t, n, x, y;
char s1[35], s2[35];
node * root;
while(scanf("%d", &t) != EOF)
{
while(t--)
{
scanf("%d", &n);
if(n == 0)
{
printf("0\n");
continue;
}
init(); num = 1;
root = newnode();
while(n--)
{
scanf("%s%s", s1, s2);
x = insert(root, s1);
y = insert(root, s2);
union_set(x, y);
printf("%d\n", a[find(y)]); //一直写成a[y],贡献出无数WA!!!
}
del(root);
}
}
return 0;
}