#include<iostream>
#include<cstdio>
#include<string.h>
#include<cstring>
#include<string>
#include<stack>
#include<set>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#define LOCAL
#define ll long long
#define lll unsigned long long
#define MAX 1000009
#define eps 1e-8
#define INF 0x7fffffff
#define mod 1000000007
using namespace std;
/*
题意:给出一颗有向树,Q个查询,输出查询点的个数
想法:LCA离线算法-Tarjan,模板题
*/
const int maxn = 1010;
const int Maxn = 500010;//查询数的最大值
int father[maxn];
int Find(int x)
{
return father[x]==-1?x:Find(father[x]);
}
void Union(int x,int y)
{
int xx = Find(x);
int yy = Find(y);
if(xx==yy) return;
father[xx] = yy;
}
bool vis[maxn*2];
int ancestor[maxn];//祖先
struct Edge
{
int to;
int next;
} edge[maxn*2];
int head[maxn],tot;
void addedge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
struct Query
{
int q,next;
int index;//查询编号
} query[Maxn*2];
int answer[Maxn];//存储最后查询的结果,下角标0~n -1
int h[Maxn];
int tt;
int Q;
void add_query(int u,int v,int index)
{
query[tt].q = v;
query[tt].next = h[u];
query[tt].index = index;
h[u] = tt++;
query[tt].q = u;
query[tt].next = h[v];
query[tt].index = index;
h[v] = tt++;
}
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
tt = 0;
memset(h,-1,sizeof(h));
memset(vis,false,sizeof(vis));
memset(father,-1,sizeof(father));
memset(ancestor,0,sizeof(ancestor));
}
void LCA(int u)
{
ancestor[u] = u;
vis[u] = true;
for(int i = head[u]; i != -1; i = edge[i].next)//与u相连接的点
{
int v = edge[i].to;
if(vis[v])continue;
LCA(v);//处理子树
Union(u,v);//然后链接到父亲
ancestor[Find(u)] = u;//子树的所有祖先都是u
}
for(int i = h[u]; i != -1; i = query[i].next)
{
int v = query[i].q;
if(vis[v])
{
answer[query[i].index] = ancestor[Find(v)];//按顺序询问,得出离线查询的顺序
}
}
}
bool flag[maxn];
int Count_num[maxn];
int main()
{
//freopen("test.in","r",stdin);
int n;
int u,v,k;
while(~scanf("%d",&n))
{
init();
memset(flag,false,sizeof(flag));
for(int i = 1; i<=n; i++)
{
scanf("%d:(%d)",&u,&k);
while(k--)
{
scanf("%d",&v);
flag[v] = true;
addedge(u,v);
addedge(v,u);
}
}
scanf("%d",&Q);
for(int i = 0; i<Q; i++)
{
char ch;
cin>>ch;
scanf("%d %d)",&u,&v);
add_query(u,v,i);
}
int root;
for(int i = 1; i<=n; i++)
{
if(!flag[i])//查找一个没有出现过得点作为初始根节点
{
root = i;
break;
}
}
LCA(root);
memset(Count_num,0,sizeof(Count_num));
for(int i = 0; i<Q; i++)
{
Count_num[answer[i]] ++;
}
for(int i = 1; i<=n; i++)
{
if(Count_num[i]>0)
{
printf("%d:%d\n",i,Count_num[i]);
}
}
}
return 0;
}
#include<cstdio>
#include<string.h>
#include<cstring>
#include<string>
#include<stack>
#include<set>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#define LOCAL
#define ll long long
#define lll unsigned long long
#define MAX 1000009
#define eps 1e-8
#define INF 0x7fffffff
#define mod 1000000007
using namespace std;
/*
题意:给出一颗有向树,Q个查询,输出查询点的个数
想法:LCA离线算法-Tarjan,模板题
*/
const int maxn = 1010;
const int Maxn = 500010;//查询数的最大值
int father[maxn];
int Find(int x)
{
return father[x]==-1?x:Find(father[x]);
}
void Union(int x,int y)
{
int xx = Find(x);
int yy = Find(y);
if(xx==yy) return;
father[xx] = yy;
}
bool vis[maxn*2];
int ancestor[maxn];//祖先
struct Edge
{
int to;
int next;
} edge[maxn*2];
int head[maxn],tot;
void addedge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
struct Query
{
int q,next;
int index;//查询编号
} query[Maxn*2];
int answer[Maxn];//存储最后查询的结果,下角标0~n -1
int h[Maxn];
int tt;
int Q;
void add_query(int u,int v,int index)
{
query[tt].q = v;
query[tt].next = h[u];
query[tt].index = index;
h[u] = tt++;
query[tt].q = u;
query[tt].next = h[v];
query[tt].index = index;
h[v] = tt++;
}
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
tt = 0;
memset(h,-1,sizeof(h));
memset(vis,false,sizeof(vis));
memset(father,-1,sizeof(father));
memset(ancestor,0,sizeof(ancestor));
}
void LCA(int u)
{
ancestor[u] = u;
vis[u] = true;
for(int i = head[u]; i != -1; i = edge[i].next)//与u相连接的点
{
int v = edge[i].to;
if(vis[v])continue;
LCA(v);//处理子树
Union(u,v);//然后链接到父亲
ancestor[Find(u)] = u;//子树的所有祖先都是u
}
for(int i = h[u]; i != -1; i = query[i].next)
{
int v = query[i].q;
if(vis[v])
{
answer[query[i].index] = ancestor[Find(v)];//按顺序询问,得出离线查询的顺序
}
}
}
bool flag[maxn];
int Count_num[maxn];
int main()
{
//freopen("test.in","r",stdin);
int n;
int u,v,k;
while(~scanf("%d",&n))
{
init();
memset(flag,false,sizeof(flag));
for(int i = 1; i<=n; i++)
{
scanf("%d:(%d)",&u,&k);
while(k--)
{
scanf("%d",&v);
flag[v] = true;
addedge(u,v);
addedge(v,u);
}
}
scanf("%d",&Q);
for(int i = 0; i<Q; i++)
{
char ch;
cin>>ch;
scanf("%d %d)",&u,&v);
add_query(u,v,i);
}
int root;
for(int i = 1; i<=n; i++)
{
if(!flag[i])//查找一个没有出现过得点作为初始根节点
{
root = i;
break;
}
}
LCA(root);
memset(Count_num,0,sizeof(Count_num));
for(int i = 0; i<Q; i++)
{
Count_num[answer[i]] ++;
}
for(int i = 1; i<=n; i++)
{
if(Count_num[i]>0)
{
printf("%d:%d\n",i,Count_num[i]);
}
}
}
return 0;
}