/* LCA 求每个点被作为最近公共祖先的次数 */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=4012;//node const int maxm=252;//query int flag[maxn],n,m,N,M,t,query,cnt[maxn],head[maxn],Head[maxn],vis[maxn],fa[maxn],NE; struct node { int u,v,d,next; }Edge[maxn*maxm],edge[maxn*maxm]; void addEdge(int u,int v) { Edge[NE].u=u,Edge[NE].v=v,Edge[NE].next=head[u]; head[u]=NE++; } void addedge(int u,int v) { edge[NE].u=u,edge[NE].v=v,edge[NE].next=Head[u]; Head[u]=NE++; } int find(int i) { return fa[i]==i?i:find(fa[i]); } void Tarjan(int u){ vis[u] = 1; fa[u] = u; for (int i = Head[u];i!=-1; i=edge[i].next){ int v=edge[i].v; if(vis[v]){ cnt[find(v)]++; // 存的是最近公共祖先结点 } } for(int i= head[u];i!=-1;i=Edge[i].next){ int v=Edge[i].v; if(!vis[v]){ Tarjan(v); fa[v] = u; } } } int main() { int i,j,u,v,root; //freopen("//media/学习/ACM/input.txt","r",stdin); while(scanf("%d", &N) != EOF){ memset(head,-1,sizeof(head)); memset(Head,-1,sizeof(Head)); memset(flag, 0, sizeof(flag)); memset(vis, 0, sizeof(vis)); memset(cnt, 0, sizeof(cnt)); for (NE=0,i = 1; i <= N; i++){ //数据的读入方式很不错啊 scanf("%d", &u); while(getchar() != '('); scanf("%d", &n); while(getchar() != ')'); while(n--){ scanf("%d", &v); flag[v] = 1; addEdge(u,v); addEdge(v,u); } } scanf("%d", &M); for (NE=0,i = 1; i <= M; i++){ while(getchar() != '('); scanf("%d%d", &u, &v); while(getchar() != ')'); addedge(u,v); addedge(v,u); } for (i = 1; i <= N; i++){// 第一个结点不一定是根结点 if(flag[i] == 0) break; } root = i; Tarjan(root); for (i = 1; i <= N; i++){ if(cnt[i]){ printf("%d:%d\n", i, cnt[i]); } } } return 0; }