#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
using namespace std;
//并查集求社交网络个数
//key:course[h]用以记录任意一个喜欢活动h的人的编号
//findFather(course[h])即该人所在社交网络的根结点

const int N=1010;
int father[N]; //存放父亲结点
int isRoot[N]={0}; //记录每个结点是否作为某个集合的根结点
int course[N]={0};
int findFather(int x){ //查找x所在集合的根结点
int a=x;
while(x != father[x]){
x=father[x];
}
//路径压缩
while(a != father[a]){
int z=a;
a=father[a];
father[z]=x;
}
return x;
}
void Union(int a,int b){ //合并a和b所在的集合
int faA=findFather(a);
int faB=findFather(b);
if(faA != faB ){
father[faA]=faB;
}
}
void init(int n){ //初始化father[i]为i,且flag[i]为false
for(int i=1;i<=n;i++){
father[i]=i;
isRoot[i]=false;
}
}
bool cmp(int a,int b){ //将isRoot数组从大到小排序
return a>b;
}

int main(){
int n,k,h;
scanf("%d",&n); //人数
init(n); //要记得初始化
for(int i=1;i<=n;i++){ //对每个人
scanf("%d:",&k); //活动个数
for(int j=0;j<k;j++){ //对每个活动
scanf("%d",&h); //输入i号人喜欢的活动h
if(course[h] == 0){ //如果活动h第一次有人喜欢
course[h]=i; //令i喜欢活动h
}
Union(i,findFather(course[h])); //合并
}
}
for(int i=1;i<=n;i++){
isRoot[findFather(i)]++; //i的根结点是findFather(i),人数加1
}
int ans=0; //记录集合的数目
for(int i=1;i<=n;i++){
if(isRoot[i] != 0){
ans++; //只统计isRoot[i]不为0的
}
}
printf("%d\n",ans); //输出集合个数
sort(isRoot+1,isRoot+n+1,cmp); //从大到小排序,所有1都在前面
for(int i=1;i<=ans;i++){ //依次输出每个集合的人数
printf("%d",isRoot[i]);
if(i < ans) printf(" ");
}
system("pause");
return 0;
}