#include <bits/stdc++.h>
using namespace std;
int gcd(int a, int b) { return a % b == 0 ? b : gcd(b, a % b); }
const long long INF = 1000000000;
const double eps = 1e-8;
const int row = 3000;
const int cow = 220;
const int MAXN = cow * cow;
int n, m, all, p, q;
long long f[200000], dp[200000];
struct node {
  long long x, v;
  bool operator<(const node k) const { return v > k.v; }
} ans[110000];
int Find(int x) {
  if (x != f[x]) f[x] = Find(f[x]);
  return f[x];
}
void Link(long long x, long long y, long long v) {
  int fx = Find(x);
  int fy = Find(y);
  if (fx == fy) {
    dp[fx] += v;
  } else {
    f[fx] = fy;
    dp[fy] += dp[fx];
    dp[fy] += v;
    all--;
  }
}
int main() {
  int i, j, t;
  scanf("%d%d%d%d", &n, &m, &p, &q);
  for (i = 1; i <= n; i++) f[i] = i;
  memset(dp, 0, sizeof(dp));
  all = n;
  bool flag = false;
  int x1, y1;
  for (i = 0; i < m; i++) {
    long long a, b, c;
    cin >> a >> b >> c;
    Link(a, b, c);
    x1 = a, y1 = b;
    flag = true;
  }
  if (all - p > q || all < q)
    printf("NO\n");
  else {
    if (m == 0 && all == q && p) {
      printf("NO\n");
      return 0;
    }
    priority_queue<node> que;
    for (i = 1; i <= n; i++) {
      if (f[i] == i) {
        node x = {i, dp[i]};
        que.push(x);
      }
    }
    for (i = 0; i < p; i++) {
      if (all == q) {
        ans[i].x = x1;
        ans[i].v = y1;
        int fx = Find(x1);
        dp[fx] += 1000;
        continue;
      }
      node x = que.top();
      que.pop();
      node y = que.top();
      que.pop();
      f[x.x] = y.x;
      dp[y.x] += dp[x.x];
      dp[y.x] += min(INF, dp[y.x] + 1);
      node w = {Find(y.x), dp[y.x]};
      all--;
      que.push(w);
      ans[i].x = x.x;
      ans[i].v = y.x;
      if (!flag) {
        x1 = x.x;
        y1 = y.x;
        flag = true;
      }
    }
    printf("YES\n");
    for (j = 0; j < p; j++) {
      cout << ans[j].x << " " << ans[j].v << endl;
    }
  }
  return 0;
}
