#include <stdio.h>
#include <string>
#include <map>
#include <vector>
using namespace std;
map<string, string> father; //编号i的父节点为j
map<string, int> height; //记录编号i的高度
string FindDisjointSet(string u) {
    if (father.find(u) != father.end()) { //father哈希表对应键u的值不为空
        if (father[u] != u) { //非根结点 ,可以进行查找操作
            father[u] = FindDisjointSet(father[u]); //寻找u的根并将父节点指向其
        }
    } else { //初始化,father哈希表对应键u的值为空
        father[u] = u; //初始的父结点指向自己
        height[u] = 0;
    }
    return father[u]; //返回集合的根结点
}
void UnionDisjointSet(string u, string v) {
    string uroot = FindDisjointSet(u); //寻找u的根结点
    string vroot = FindDisjointSet(v);//寻找v的根结点
    if (uroot != vroot) { //不合并才可以操作
        if (height[uroot] > height[vroot]) { //小数并入大树
            father[vroot] = uroot;
        } else if (height[uroot] < height[vroot]) { //小数并入大树
            father[uroot] = uroot;
        } else { //高度一致随便合并假设u为上,v为下 //初始时高度均一致
            father[vroot] = uroot;
            height[vroot]++; //并合并的集合树高+1
        }
    }
}
int main() {
    int n, k;
    int setCount; //记录团伙的数目
    while (scanf("%d%d", &n,
                 &k) != EOF) { //电话的数量和权值(理解为边的权值)
        map<string, int> SetMap; //存储每个名字对应的权值
        vector<string> root; //记录每个集合(团伙)根结点
        setCount = 0;
        for (int i = 0; i < n; i++) {
            char name1[20];
            char name2[20];
            int time;
            scanf("%s%s%d", name1, name2, &time);
            SetMap[name1] += time; //权值 = 时间累加
            SetMap[name2] += time;
            UnionDisjointSet(name1, name2); //以名字作为编号合并
        }
        auto it = father.begin();
        for (it = father.begin(); it != father.end(); it++) {
            //找出每个集合(团伙)的根结点便于分出有几个团伙!
            if (it->first == it->second) {
                root.push_back(it->first);
            }
        }
        auto it1 = SetMap.begin();
        //记录根结点以及对应集合的各个元素(人)
        vector<vector<string>> Set(root.size(), vector<string>(SetMap.size()));
        //记录每个集合(团伙)的总权值
        vector<float> weight(root.size());
        for (int i = 0; i < root.size();
                i++) {//根结点以及对应集合的各个元素(人)
            int j = 0;
            for (it1 = SetMap.begin(); it1 != SetMap.end(); it1++) { //每个结点及时间
                //从结点-时间哈希表头开始遍历,根结点一样则属于一个集合i(团伙)
                if (FindDisjointSet(it1->first) == root[i]) {
                    Set[i][j] = it1->first; //将对应的键即名字放入同一个集合
                    //团伙总权值的计算
                    weight[i] += float(SetMap[Set[i][j]]) /
                                 2; //算总时间的时候多加了一半要/2
                    j++;
                }
            }
        }
        for (int i = 0; i < root.size(); i++) { //外层循环
            int l = 0; //记录每个集合(团伙)的个数
            for (int j = 0; j < Set[i].size(); j++) { //内存循环
                if (!Set[i][j].empty()) {
                    l++;
                }
            }
            if (l > 2 && weight[i] > k) { //判断是否为团伙,1.成员>2 2.总权值>k
                setCount++;
            }
        }
        if (setCount > 0) { //先输出当前团伙的个数
            printf("%d\n", setCount);
        } else {//若当前团伙的个数为0 后序的寻找团伙头目无需再进行!直接结束本次循环
            printf("0\n");
            continue;
        }
        map<string, int>
        Result; //按字母顺序记录最终的团伙头目及对应团伙成员数
        for (int i = 0; i < root.size(); i++) {
            int Maxcount = 0; //记录哪个人的权值最大?--》头目
            string MaxString; //更新最大权值对应的人(名字)
            int l = 0; //记录每个团伙的成员数
            for (int j = 0; j < Set[i].size(); j++) {
                if (!Set[i][j].empty()) {
                    l++;
                }
            }
            if (l > 2 && weight[i] > k) { //满足团伙条件才将结果进行保存
                for (int r = 0; r < Set[i].size(); r++) {
                    if (SetMap[Set[i][r]] > Maxcount) {
                        Maxcount = SetMap[Set[i][r]];
                        MaxString = Set[i][r];
                    }
                }
                //将结果插入一个有序哈希表 即按罪犯头目名字的字母从小到大顺序进行存储
                Result.insert({MaxString.c_str(), l});
            }
        }
        auto it2 = Result.begin();
        //最后按序输出名字及对应的集合大小
        for (it2 = Result.begin(); it2 != Result.end(); it2++) {
            printf("%s %d\n", it2->first.c_str(), it2->second);
        }
    }
    return 0;
}