#include <unordered_map>
#include <vector>
#include <iostream>
#include <utility>
#include <functional>
#include <iomanip>

using namespace std;

void solve(int n, int k)
{
    vector<int> v(n);
    int i;
    int weeks = n - k + 1;
    int h = 0;
    int h_tot = 0;
    double res;

    for(int i=0; i<n; i++)
        cin >> v[i];

    for(i=0; i<k; i++)
        h += v[i];

    h_tot += h;
    for(i=1; i<weeks; i++)
    {
        h = h - v[i-1] + v[i+k-1];
        h_tot += h;
    }

    res = h_tot/((double)weeks);
    cout << fixed << setprecision(9);
    cout << res << endl;
}

int main()
{
    int n, k;

    cin >> n;
    cin >> k;
    solve(n, k);

    return 0;
}

// 1495217313961


#include <iostream>
#include <iomanip>

#define min3(x, y, z) min(x, min(y, z))

using namespace std;

int main(){
  ios::sync_with_stdio(false);
  int n, k;
  cin >> n >> k;
  double av = 0;
  double acc = 0;
  double *a = new double[n];
  for(int i = 0; i < n; i++)
    cin >> a[i];

  for(int i = 0; i < k; i++)
    acc += a[i];

  av = acc;
  for(int i = k; i < n; i++){
    acc = acc + a[i] - a[i - k];
    av += acc;
  }

  cout << fixed << setprecision(10) << av / (n - k + 1) << endl;

  return 0;
}

// 1495215734283


#include <iostream>
#include <vector>
#include <iomanip>

using namespace std;

int main(){

    int n, k;

    cin >> n >> k;

    double nweeks = (double) n - k + 1;

    double m = 0;

    vector<long long> a(n);
    vector<double> weeks(nweeks);

    for(int i = 0; i < n; i++){
        cin >> a[i];
    }

    long long semana = 0;
    long long t = 0;

    int si = 0;
    int ei = k-1;
    for(int i = 0; i < nweeks; i++){
        semana = 0ll;
        for(int j = si; j <= ei; j++){
            semana += a[j];
        }

        weeks[i] = (double) (semana / nweeks);

        si = ei;
        ei = ei + k - 1;
    }

    for(int i = 0; i < nweeks; i++){
        m += weeks[i];
    }

    /*
     for(int i = 0; i < n; i++){
     semana += a[i];
     d++;

     // fim de outra semana
     if(d == k){
     aux = (double) semana / nweeks;
     m += aux;
     semana = a[i];
     d = 1;
     }
     }*/

    std::cout << std::fixed;
    std::cout << std::setprecision(13);
    std::cout << m << endl;
}
// 1496252034623


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <sstream>
#define lint long long
using namespace std;
int n, m, p, q;

#define lint long long
#define MAX 100007
int uf[MAX];
lint cost[MAX];
set<pair<lint,int> > Q;
set<int> rep;
vector<pair<int,int> > res;
const lint mc = 1000000000LL;

lint sum;
int FIND(int x){ return uf[x]==x? x:uf[x] = FIND(uf[x]); }
void UNION1(int x,int y, lint c){
  int fx = FIND(x);
  int fy = FIND(y);
  lint nc=-1;

  if(fx == fy){
    nc = (cost[fy]+c);
    Q.erase(make_pair(cost[fy], fy));
    Q.insert(make_pair(min(nc, mc), fy));
    cost[fy] = nc;
  }else{
    nc = cost[fx]+cost[fy]+c;
    rep.erase(fx);
    Q.erase(make_pair(cost[fx], fx));
    Q.erase(make_pair(cost[fy], fy));
    Q.insert(make_pair(nc, fy));

    uf[fx] = fy;
    cost[fy] = nc;
  }
  sum+= nc;
}

void UNION2(int x,int y){
  int fx = FIND(x);
  int fy = FIND(y);

  if(fx < fy) swap(fx,fy);

  lint nc = cost[fx]+cost[fy]+min(cost[fx]+cost[fy]+1,mc);

  rep.erase(fx);
  Q.erase(make_pair(cost[fx], fx));
  Q.erase(make_pair(cost[fy], fy));

  Q.insert(make_pair(nc, fy));

  uf[fx] = fy;
  cost[fy] = nc;
  sum+= nc;
}

void init(int n){
  for(int i = 0; i < n; i++){
    uf[i] = i;
    cost[i] = 0;
    rep.insert(i);
    Q.insert(make_pair(0,i));
  }
}

int main(){
  int u,v;
  lint c;

  cin >> n >> m >> p >> q;

  init(n);
  for(int i = 0; i < m; i++){
    cin >> u >> v >> c;
    u--;v--;
    UNION1(u,v,c);
  }
  int k = 0;
  for(int i = rep.size(); i > q && p > 0; i--){

    /*
    for (std::set<pair<lint,int > >::iterator it=Q.begin(); it!=Q.end(); ++it){
      printf("(%d %lld) ",  (*it).second+1, (*it).first);
    }cout << endl;*/

    ////printf("(%d %lld, %d %lld)\n", (*Q.begin()).second, (*Q.begin()).first, (*(++Q.begin())).second, (*(++Q.begin())).first);
    u = (*Q.begin()).second;
    v = (*(++Q.begin())).second;
    //cout << u+1 << " " << v+1 << endl;
    UNION2(u,v);
    res.push_back(make_pair(u,v));
    p--;
  }

  while(p > 0){
    res.push_back(make_pair(u,v));
    p--;
    sum+=1000;
  }
  //cout << sum << endl;
  if(rep.size() == q && p == 0){
    printf("YES\n");
    for(int i = 0; i < res.size(); i++){
      printf("%d %d\n", res[i].first+1, res[i].second+1);
    }
  }else{
    printf("NO\n");
  }

  return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <sstream>
#define lint long long
using namespace std;
int n, m, p, q;
int a;

#define MAX 100005
int uf[MAX];
int cost[MAX];
set<pair<int,int> > Q;
set<int> rep;
vector<pair<int,int> > res;

int FIND(int x){ return uf[x]==x? x:uf[x] = FIND(uf[x]); }
void UNION1(int x,int y, int c){
  int fx = FIND(x);
  int fy = FIND(y);
  int nc;

  if(fx == fy){
    nc = cost[fx]+c;
    Q.erase(make_pair(cost[fy], fy));
    Q.insert(make_pair(min(nc, (int)1e9), fy));
    cost[fy] = min(nc, (int)1e9);
    return;
  }

  nc = cost[fx]+cost[fy]+c;
  rep.erase(fx);
  Q.erase(make_pair(cost[fx], fx));
  Q.erase(make_pair(cost[fy], fy));
  Q.insert(make_pair(min(nc, (int)1e9), fy));

  uf[fx] = fy;
  cost[fy] = min(nc, (int)1e9);
}

void UNION2(int x,int y){
  int fx = FIND(x);
  int fy = FIND(y);
  int c = min(cost[fx]+cost[fy]+1,(int)1e9);

  rep.erase(fx);
  Q.erase(make_pair(cost[fx], fx));
  Q.erase(make_pair(cost[fy], fy));

  Q.insert(make_pair(c, fy));

  uf[fx] = fy;
  cost[fy] = c;
}

void init(int n){
  for(int i = 0; i < n; i++){
    uf[i] = i;
    cost[i] = 0;
    rep.insert(i);
    Q.insert(make_pair(0,i));
  }
}

int t2[MAX];
bool unir(){
  set<int> r2;
  int u = -1, v = -1;
  for(int i = 0; i < n; i++){
    if(r2.count(FIND(i)) > 0){
      u = t2[FIND(i)];
      v = i;
    }
    t2[FIND(i)] = i;
    r2.insert(FIND(i));
  }
  if(u == -1 || v == -1) return false;
  while(p > 0){
    res.push_back(make_pair(u,v));
    p--;
  }
}
int main(){
  int u,v,c;
  cin >> n >> m >> p >> q;
  a = 0;
  init(n);
  for(int i = 0; i < m; i++){
    cin >> u >> v >> c;
    u--;v--;
    UNION1(u,v,c);
  }

  for(int i = rep.size(); i > q && p > 0; i--){
    /*for (std::set<pair<int,int > >::iterator it=Q.begin(); it!=Q.end(); ++it){
      printf("(%d %d) ",  (*it).second+1, (*it).first);
    }cout << endl;
    return 0;*/
    u = (*Q.begin()).second;
    v = (*(++Q.begin())).second;
    //cout << u+1 << " " << v+1 << endl;
    UNION2(u,v);
    res.push_back(make_pair(u,v));
    p--;
  }

  if(p > 0){
    unir();
  }
  if(rep.size() == q && p == 0){
    printf("YES\n");
    for(int i = 0; i < res.size(); i++){
      printf("%d %d\n", res[i].first+1, res[i].second+1);
    }
  }else{
    printf("NO\n");
  }

  return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <sstream>
#define lint long long
using namespace std;
int n, m, p, q;
int a;

#define MAX 100005
int uf[MAX];
int cost[MAX];
set<pair<int,int> > Q;
set<int> rep;
vector<pair<int,int> > res;

int FIND(int x){ return uf[x]==x? x:uf[x] = FIND(uf[x]); }
void UNION1(int x,int y, int c){
  int fx = FIND(x);
  int fy = FIND(y);
  int nc;
  if(fx == fy){
    nc = c;
    Q.erase(make_pair(cost[fy], fy));
    Q.insert(make_pair(cost[fy]+c, fy));
    cost[fy] = cost[fx]+c;
    return;
  }

  rep.erase(fx);
  Q.erase(make_pair(cost[fx], fx));
  Q.erase(make_pair(cost[fy], fy));
  Q.insert(make_pair(cost[fx]+cost[fy]+c, fy));

  uf[fx] = fy;
  cost[fy] = cost[fx]+cost[fy]+c;
}

void UNION2(int x,int y, int c){
  int fx = FIND(x);
  int fy = FIND(y);
  rep.erase(fx);
  Q.erase(make_pair(cost[fx], fx));
  Q.erase(make_pair(cost[fy], fy));

  Q.insert(make_pair(c, fy));

  uf[fx] = fy;
  cost[fy] = c;
}

void init(int n){
  for(int i = 0; i < n; i++){
    uf[i] = i;
    cost[i] = 0;
    rep.insert(i);
    Q.insert(make_pair(0,i));
  }
}

int t2[MAX];
bool unir(){
  set<int> r2;
  int u = -1, v = -1;
  for(int i = 0; i < n; i++){
    if(r2.count(FIND(i)) > 0){
      u = t2[FIND(i)];
      v = i;
    }
    t2[FIND(i)] = i;
    r2.insert(FIND(i));
  }
  if(u == -1 || v == -1) return false;
  while(p > 0){
    res.push_back(make_pair(u,v));
    p--;
  }
}
int main(){
  int u,v,c;
  cin >> n >> m >> p >> q;
  a = 0;
  init(n);
  for(int i = 0; i < m; i++){
    cin >> u >> v >> c;
    u--;v--;
    UNION1(u,v,c);
  }

  for(int i = rep.size(); i > q && p > 0; i--){
    /*for (std::set<pair<int,int > >::iterator it=Q.begin(); it!=Q.end(); ++it){
      printf("(%d %d) ",  (*it).second+1, (*it).first);
    }cout << endl;
    return 0;*/
    u = (*Q.begin()).second;
    v = (*(++Q.begin())).second;
    //cout << u+1 << " " << v+1 << endl;
    UNION1(u,v, min(cost[FIND(u)]+cost[FIND(v)]+1,(int)1e9) );
    res.push_back(make_pair(u,v));
    p--;
  }

  if(p > 0){
    unir();
  }
  if(rep.size() == q && p == 0){
    printf("YES\n");
    for(int i = 0; i < res.size(); i++){
      printf("%d %d\n", res[i].first+1, res[i].second+1);
    }
  }else{
    printf("NO\n");
  }

  return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <sstream>
#define lint long long
using namespace std;
int n, m, p, q;
int a;
#define lint long long
#define MAX 100005
int uf[MAX];
lint cost[MAX];
set<pair<lint,int> > Q;
set<int> rep;
vector<pair<int,int> > res;
const lint mc = (lint)1e8;

lint sum;
int FIND(int x){ return uf[x]==x? x:uf[x] = FIND(uf[x]); }
void UNION1(int x,int y, lint c){
  int fx = FIND(x);
  int fy = FIND(y);
  lint nc;

  if(fx == fy){
    nc = cost[fx]+c;
    Q.erase(make_pair(cost[fy], fy));
    Q.insert(make_pair(min(nc, mc), fy));
    cost[fy] = min(nc, mc);
  }else{
    nc = cost[fx]+cost[fy]+c;
    rep.erase(fx);
    Q.erase(make_pair(cost[fx], fx));
    Q.erase(make_pair(cost[fy], fy));
    Q.insert(make_pair(min(nc, mc), fy));

    uf[fx] = fy;
    cost[fy] = min(nc, mc);
  }
  sum+= nc;
}

void UNION2(int x,int y){
  int fx = FIND(x);
  int fy = FIND(y);
  lint c = min(cost[fx]+cost[fy]+1,mc);

  rep.erase(fx);
  Q.erase(make_pair(cost[fx], fx));
  Q.erase(make_pair(cost[fy], fy));

  Q.insert(make_pair(c, fy));

  uf[fx] = fy;
  cost[fy] = c;
  sum+= c;
}

void init(int n){
  for(int i = 0; i < n; i++){
    uf[i] = i;
    cost[i] = 0;
    rep.insert(i);
    Q.insert(make_pair(0,i));
  }
}

int t2[MAX];
bool unir(){
  set<int> r2;
  int u = -1, v = -1;
  for(int i = 0; i < n; i++){
    if(r2.count(FIND(i)) > 0){
      u = t2[FIND(i)];
      v = i;
    }
    t2[FIND(i)] = i;
    r2.insert(FIND(i));
  }
  if(u == -1 || v == -1) return false;
  while(p > 0){
    res.push_back(make_pair(u,v));
    p--;
    sum+=1000;
  }
}

int main(){
  int u,v;
  lint c;
  cin >> n >> m >> p >> q;
  a = 0;
  init(n);
  for(int i = 0; i < m; i++){
    cin >> u >> v >> c;
    u--;v--;
    UNION1(u,v,c);
  }

  for(int i = rep.size(); i > q && p > 0; i--){
    /*for (std::set<pair<int,int > >::iterator it=Q.begin(); it!=Q.end(); ++it){
      printf("(%d %d) ",  (*it).second+1, (*it).first);
    }cout << endl;
    return 0;*/

    //printf("(%d %lld, %d %lld)\n", (*Q.begin()).second, (*Q.begin()).first, (*(++Q.begin())).second, (*(++Q.begin())).first);
    u = (*Q.begin()).second;
    v = (*(++Q.begin())).second;
    //cout << u+1 << " " << v+1 << endl;
    UNION2(u,v);
    res.push_back(make_pair(u,v));
    p--;
  }

  if(p > 0){
    unir();
  }
  //cout << sum << endl;
  if(rep.size() == q && p == 0){
    printf("YES\n");
    for(int i = 0; i < res.size(); i++){
      printf("%d %d\n", res[i].first+1, res[i].second+1);
    }
  }else{
    printf("NO\n");
  }

  return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int n, m, p, q;
int par[100100];
int rnk[100100];
int sz[100100];
int from = -1, to = -1;
multiset<pair<ll, ll> > s;
vector<int> G[100100];
int vis[100100];

void init(){
	for (int i = 1; i <= n; i++){
		par[i] = i;
		rnk[i] = 0;
		sz[i] = 1;
		s.insert(make_pair(1, i));
	}
}

int findSet(int u){
	if (par[u] == u) return u;
	return par[u] = findSet(par[u]);
}

int isSame(int u, int v){
	return (findSet(u) == findSet(v));
}

void merge(int u, int v){
	int x = findSet(u), y = findSet(v);
	if (x == y) return;
	if (rnk[x] < rnk[y]){
		s.erase(s.find(make_pair(sz[y], y)));
		s.erase(s.find(make_pair(sz[x], x)));
		par[x] = y;
		sz[y] += sz[x];
		s.insert(make_pair(sz[y], y));
	}
	else{
		s.erase(s.find(make_pair(sz[y], y)));
		s.erase(s.find(make_pair(sz[x], x)));
		par[y] = x;
		sz[x] += sz[y];
		s.insert(make_pair(sz[x], x));
		if (rnk[x] == rnk[y]) rnk[x]++;
	}
}

ll size(int u){
	return sz[findSet(u)];
}

void addSize(int u, int len){
	int x = findSet(u);
	s.erase(s.find(make_pair(sz[x], x)));
	sz[x] += len;
	s.insert(make_pair(sz[x], x));
}

int main() {
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m >> p >> q;
	init();
	for (int i = 0; i < m; i++){
		int a, b, w; cin >> a >> b >> w;
		G[a].push_back(b);
		G[b].push_back(a);
		from = a, to = b;
		merge(a, b);
		addSize(a, w);
	}
	int nowHave = s.size();
	if (q > nowHave) return cout << "NO" << endl, 0;
	if (nowHave - p > q) return cout << "NO" << endl, 0;
	if (q == nowHave){
		if (m == 0 && p != 0) return cout << "NO" << endl, 0;
		if (m == 0 && p == 0) return cout << "YES" << endl, 0;
	}
	cout << "YES" << endl;
	int needToBuild = nowHave - q;
	for (int i = 0; i < needToBuild; i++){
		multiset<pair<ll, ll> >::iterator it = s.begin();
		ll size1 = it->first, id1 = it->second;
		it++;
		ll size2 = it->first, id2 = it->second;
		cout << id1 << " " << id2 << endl;
		merge(id1, id2);
		addSize(id1, min(1000000000LL, size1 + size2 + 1));
	}
	for (int i = 0; i < p - needToBuild; i++){
		cout << from << " " << to << endl;
	}

	return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int n, m, p, q;
int par[100100];
int rnk[100100];
ll sz[100100];
int from = 1, to = 2;
multiset<pair<ll, ll> > s;
vector<int> G[100100];
int vis[100100];

void init(){
	for (int i = 1; i <= n; i++){
		par[i] = i;
		rnk[i] = 0;
		sz[i] = 1;
		s.insert(make_pair(1, i));
	}
}

int findSet(int u){
	if (par[u] == u) return u;
	return par[u] = findSet(par[u]);
}

int isSame(int u, int v){
	return (findSet(u) == findSet(v));
}

void merge(int u, int v){
	int x = findSet(u), y = findSet(v);
	if (x == y) return;
	if (rnk[x] < rnk[y]){
		s.erase(s.find(make_pair(sz[y], y)));
		s.erase(s.find(make_pair(sz[x], x)));
		par[x] = y;
		sz[y] += sz[x];
		s.insert(make_pair(sz[y], y));
	}
	else{
		s.erase(s.find(make_pair(sz[y], y)));
		s.erase(s.find(make_pair(sz[x], x)));
		par[y] = x;
		sz[x] += sz[y];
		s.insert(make_pair(sz[x], x));
		if (rnk[x] == rnk[y]) rnk[x]++;
	}
}

ll size(int u){
	return sz[findSet(u)];
}

void addSize(int u, int len){
	int x = findSet(u);
	s.erase(s.find(make_pair(sz[x], x)));
	sz[x] += len;
	s.insert(make_pair(sz[x], x));
}

int main() {
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m >> p >> q;
	init();
	for (int i = 0; i < m; i++){
		int a, b, w; cin >> a >> b >> w;
		G[a].push_back(b);
		G[b].push_back(a);
		from = a, to = b;
		merge(a, b);
		addSize(a, w);
	}
	int nowHave = s.size();
	if (q > nowHave) return cout << "NO" << endl, 0;
	if (nowHave - p > q) return cout << "NO" << endl, 0;
	if (q == nowHave){
		if (m == 0 && p != 0) return cout << "NO" << endl, 0;
		if (m == 0 && p == 0) return cout << "YES" << endl, 0;
	}
	cout << "YES" << endl;
	int needToBuild = nowHave - q;
	for (int i = 0; i < needToBuild; i++){
		multiset<pair<ll, ll> >::iterator it = s.begin();
		ll size1 = it->first, id1 = it->second;
		it++;
		ll size2 = it->first, id2 = it->second;
		cout << id1 << " " << id2 << endl;
		merge(id1, id2);
		addSize(id1, min(1000000000LL, size1 + size2 + 1));
	}
	for (int i = 0; i < p - needToBuild; i++){
		cout << from << " " << to << endl;
	}

	return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int n, m, p, q;
int par[100100];
int rnk[100100];
ll sz[100100];
int from = 1, to = 2;
multiset<pair<ll, ll> > s;
vector<int> G[100100];

void init(){
	for (int i = 1; i <= n; i++){
		par[i] = i;
		rnk[i] = 0;
		sz[i] = 0;
		s.insert(make_pair(0, i));
	}
}

int findSet(int u){
	if (par[u] == u) return u;
	return par[u] = findSet(par[u]);
}

int isSame(int u, int v){
	return (findSet(u) == findSet(v));
}

void merge(int u, int v){
	int x = findSet(u), y = findSet(v);
	if (x == y) return;
	if (rnk[x] < rnk[y]){
		s.erase(s.find(make_pair(sz[y], y)));
		s.erase(s.find(make_pair(sz[x], x)));
		par[x] = y;
		sz[y] += sz[x];
		s.insert(make_pair(sz[y], y));
	}
	else{
		s.erase(s.find(make_pair(sz[y], y)));
		s.erase(s.find(make_pair(sz[x], x)));
		par[y] = x;
		sz[x] += sz[y];
		s.insert(make_pair(sz[x], x));
		if (rnk[x] == rnk[y]) rnk[x]++;
	}
}

ll size(int u){
	return sz[findSet(u)];
}

void addSize(int u, ll len){
	int x = findSet(u);
	s.erase(s.find(make_pair(sz[x], x)));
	sz[x] += len;
	s.insert(make_pair(sz[x], x));
}

int main() {
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m >> p >> q;
	init();
	for (int i = 0; i < m; i++){
		int a, b, w; cin >> a >> b >> w;
		G[a].push_back(b);
		G[b].push_back(a);
		from = a, to = b;
		merge(a, b);
		addSize(a, w);
	}
	int nowHave = s.size();
	if (q > nowHave) return cout << "NO" << endl, 0;
	if (nowHave - p > q) return cout << "NO" << endl, 0;
	if (q == nowHave){
		if (m == 0 && p != 0) return cout << "NO" << endl, 0;
		if (m == 0 && p == 0) return cout << "YES" << endl, 0;
	}
	cout << "YES" << endl;
	int needToBuild = nowHave - q;
	for (int i = 0; i < needToBuild; i++){
		multiset<pair<ll, ll> >::iterator it = s.begin();
		ll size1 = it->first, id1 = it->second;
		it++;
		ll size2 = it->first, id2 = it->second;
		cout << id1 << " " << id2 << endl;
		merge(id1, id2);
		addSize(id1, min(1000000000LL, size1 + size2 + 1));
		from = id1, to = id2;
	}
	for (int i = 0; i < p - needToBuild; i++){
		cout << from << " " << to << endl;
	}

	return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int n, m, p, q;
int par[100100];
int rnk[100100];
ll sz[100100];
int from = -1, to = -1;
multiset<pair<ll, ll> > s;
vector<int> G[100100];
int vis[100100];

void init(){
	for (int i = 1; i <= n; i++){
		par[i] = i;
		rnk[i] = 0;
		sz[i] = 1;
		s.insert(make_pair(1, i));
	}
}

int findSet(int u){
	if (par[u] == u) return u;
	return par[u] = findSet(par[u]);
}

int isSame(int u, int v){
	return (findSet(u) == findSet(v));
}

void merge(int u, int v){
	int x = findSet(u), y = findSet(v);
	if (x == y) return;
	if (rnk[x] < rnk[y]){
		s.erase(s.find(make_pair(sz[y], y)));
		s.erase(s.find(make_pair(sz[x], x)));
		par[x] = y;
		sz[y] += sz[x];
		s.insert(make_pair(sz[y], y));
	}
	else{
		s.erase(s.find(make_pair(sz[y], y)));
		s.erase(s.find(make_pair(sz[x], x)));
		par[y] = x;
		sz[x] += sz[y];
		s.insert(make_pair(sz[x], x));
		if (rnk[x] == rnk[y]) rnk[x]++;
	}
}

ll size(int u){
	return sz[findSet(u)];
}

void addSize(int u, int len){
	int x = findSet(u);
	s.erase(s.find(make_pair(sz[x], x)));
	sz[x] += len;
	s.insert(make_pair(sz[x], x));
}

int main() {
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m >> p >> q;
	init();
	for (int i = 0; i < m; i++){
		int a, b, w; cin >> a >> b >> w;
		G[a].push_back(b);
		G[b].push_back(a);
		from = a, to = b;
		merge(a, b);
		addSize(a, w);
	}
	int nowHave = s.size();
	if (q > nowHave) return cout << "NO" << endl, 0;
	if (nowHave - p > q) return cout << "NO" << endl, 0;
	if (q == nowHave){
		if (m == 0 && p != 0) return cout << "NO" << endl, 0;
		if (m == 0 && p == 0) return cout << "YES" << endl, 0;
	}
	cout << "YES" << endl;
	int needToBuild = nowHave - q;
	for (int i = 0; i < needToBuild; i++){
		multiset<pair<ll, ll> >::iterator it = s.begin();
		ll size1 = it->first, id1 = it->second;
		it++;
		ll size2 = it->first, id2 = it->second;
		cout << id1 << " " << id2 << endl;
		merge(id1, id2);
		addSize(id1, min(1000000000LL, size1 + size2 + 1));
	}
	for (int i = 0; i < p - needToBuild; i++){
		cout << from << " " << to << endl;
	}

	return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int n, m, p, q;
int par[100100];
int rnk[100100];
ll sz[100100];
int from = 1, to = 2;
multiset<pair<ll, ll> > s;
vector<int> G[100100];

void init(){
	for (int i = 1; i <= n; i++){
		par[i] = i;
		rnk[i] = 0;
		sz[i] = 0;
		s.insert(make_pair(1, i));
	}
}

int findSet(int u){
	if (par[u] == u) return u;
	return par[u] = findSet(par[u]);
}

int isSame(int u, int v){
	return (findSet(u) == findSet(v));
}

void merge(int u, int v){
	int x = findSet(u), y = findSet(v);
	if (x == y) return;
	if (rnk[x] < rnk[y]){
		s.erase(s.find(make_pair(sz[y], y)));
		s.erase(s.find(make_pair(sz[x], x)));
		par[x] = y;
		sz[y] += sz[x];
		s.insert(make_pair(sz[y], y));
	}
	else{
		s.erase(s.find(make_pair(sz[y], y)));
		s.erase(s.find(make_pair(sz[x], x)));
		par[y] = x;
		sz[x] += sz[y];
		s.insert(make_pair(sz[x], x));
		if (rnk[x] == rnk[y]) rnk[x]++;
	}
}

ll size(int u){
	return sz[findSet(u)];
}

void addSize(int u, ll len){
	int x = findSet(u);
	s.erase(s.find(make_pair(sz[x], x)));
	sz[x] += len;
	s.insert(make_pair(sz[x], x));
}

int main() {
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m >> p >> q;
	init();
	for (int i = 0; i < m; i++){
		int a, b, w; cin >> a >> b >> w;
		G[a].push_back(b);
		G[b].push_back(a);
		from = a, to = b;
		merge(a, b);
		addSize(a, w);
	}
	int nowHave = s.size();
	if (q > nowHave) return cout << "NO" << endl, 0;
	if (nowHave - p > q) return cout << "NO" << endl, 0;
	if (q == nowHave){
		if (m == 0 && p != 0) return cout << "NO" << endl, 0;
		if (m == 0 && p == 0) return cout << "YES" << endl, 0;
	}
	cout << "YES" << endl;
	int needToBuild = nowHave - q;
	for (int i = 0; i < needToBuild; i++){
		multiset<pair<ll, ll> >::iterator it = s.begin();
		ll size1 = it->first, id1 = it->second;
		it++;
		ll size2 = it->first, id2 = it->second;
		cout << id1 << " " << id2 << endl;
		merge(id1, id2);
		addSize(id1, min(1000000000LL, size1 + size2 + 1));
		from = id1, to = id2;
	}
	for (int i = 0; i < p - needToBuild; i++){
		cout << from << " " << to << endl;
	}

	return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int n, m, p, q;
int par[100100];
int rnk[100100];
ll sz[100100];
int from = 1, to = 2;
multiset<pair<ll, ll> > s;
vector<int> G[100100];
int vis[100100];

void init(){
	for (int i = 1; i <= n; i++){
		par[i] = i;
		rnk[i] = 0;
		sz[i] = 1;
		s.insert(make_pair(1, i));
	}
}

int findSet(int u){
	if (par[u] == u) return u;
	return par[u] = findSet(par[u]);
}

int isSame(int u, int v){
	return (findSet(u) == findSet(v));
}

void merge(int u, int v){
	int x = findSet(u), y = findSet(v);
	if (x == y) return;
	if (rnk[x] < rnk[y]){
		s.erase(s.find(make_pair(sz[y], y)));
		s.erase(s.find(make_pair(sz[x], x)));
		par[x] = y;
		sz[y] += sz[x];
		s.insert(make_pair(sz[y], y));
	}
	else{
		s.erase(s.find(make_pair(sz[y], y)));
		s.erase(s.find(make_pair(sz[x], x)));
		par[y] = x;
		sz[x] += sz[y];
		s.insert(make_pair(sz[x], x));
		if (rnk[x] == rnk[y]) rnk[x]++;
	}
}

ll size(int u){
	return sz[findSet(u)];
}

void addSize(int u, int len){
	int x = findSet(u);
	s.erase(s.find(make_pair(sz[x], x)));
	sz[x] += len;
	s.insert(make_pair(sz[x], x));
}

int main() {
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m >> p >> q;
	init();
	for (int i = 0; i < m; i++){
		int a, b, w; cin >> a >> b >> w;
		G[a].push_back(b);
		G[b].push_back(a);
		from = a, to = b;
		merge(a, b);
		addSize(a, w);
	}
	int nowHave = s.size();
	if (q > nowHave) return cout << "NO" << endl, 0;
	if (nowHave - p > q) return cout << "NO" << endl, 0;
	if (q == nowHave){
		if (m == 0 && p != 0) return cout << "NO" << endl, 0;
		if (m == 0 && p == 0) return cout << "YES" << endl, 0;
	}
	cout << "YES" << endl;
	int needToBuild = nowHave - q;
	for (int i = 0; i < needToBuild; i++){
		multiset<pair<ll, ll> >::iterator it = s.begin();
		ll size1 = it->first, id1 = it->second;
		it++;
		ll size2 = it->first, id2 = it->second;
		cout << id1 << " " << id2 << endl;
		merge(id1, id2);
		addSize(id1, min(1000000000LL, size1 + size2 + 1));
		from = id1, to = id2;
	}
	for (int i = 0; i < p - needToBuild; i++){
		cout << from << " " << to << endl;
	}

	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x, val;
    par( int _x = 0, int _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

int HOW[ N ], comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = -1, x2 = -1;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp < q ) { printf( "NO\n" ); return; }
    if( comp - p < q && x1 == -1 ) { printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( comp != q) {
        int x = S.begin( ) -> x;
        int val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        int val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, min( val + val2 + 1 , 1000000000 ) + val + val2 ) );
        HOW[ x ] = min( val + val2 + 1 , 1000000000 ) + val + val2;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        comp--;
        p--;
    }
    printf( "dad\n" );
    while( p >= 1 ) printf( "%d %d\n", x1, x2 ), p--;
}

int main( void ) {
    load( );
    solve( );
   // system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

typedef long long llint;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x;
    llint val;
    par( int _x = 0, llint _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

llint HOW[ N ];
int comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = -1, x2 = -1;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline llint minic( const llint &A, const llint &B ) { return A > B ? A : B; }

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp < q ) { printf( "NO\n" ); return; }
    if( comp == n && p ){ printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( p ) {
        if( comp == 0 ) {
            printf( "%d %d\n", x1, x2 );
            p--;
            continue;
        }
        int x = S.begin( ) -> x;
        llint val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        llint val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, minic( val + val2 + 1, 1000000000 ) + val + val2 ) );
        HOW[ x ] = minic( val + val2 + 1, 1000000000 ) + val + val2;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        comp--;
    }
   // while( p >= 1 ) printf( "%d %d\n", x1, x2 ), p--;
}

int main( void ) {
    load( );
    solve( );
    //system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x, val;
    par( int _x = 0, int _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

int HOW[ N ], comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = -1, x2 = -1;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp < q ) { printf( "NO\n" ); return; }
    if( comp - p < q && x1 == -1 ) { printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( comp != q) {
        int x = S.begin( ) -> x;
        int val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        int val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, min( val + val2 + 1 , 1000000000 ) + val + val2 ) );
        HOW[ x ] = min( val + val2 + 1 , 1000000000 ) + val + val2;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        comp--;
        p--;
    }
  //  printf( "dad\n" );
    while( p >= 1 ) printf( "%d %d\n", x1, x2 ), p--;
}

int main( void ) {
    load( );
    solve( );
   // system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

typedef long long llint;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x;
    llint val;
    par( int _x = 0, llint _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

llint HOW[ N ];
int comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = -1, x2 = -1;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline llint minic( const llint &A, const llint &B ) { return A < B ? A : B; }

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp < q ) { printf( "NO\n" ); return; }
    if( ( comp == n && comp == q && p ) ){ printf( "NO\n" ); return; }
   // for( set< par > :: iterator it = S.begin( ); it != S.end( ); it++ ) printf( "%d %d\n", it -> x, it -> val );

    printf( "YES\n" );
    while( p ) {
        if( comp == q ) {
            printf( "%d %d\n", x1, x2 );
            p--;
            continue;
        }
        int x = S.begin( ) -> x;
        llint val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        llint val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        llint sol = minic( val + val2 + 1, 1000000000 ) + val + val2 ;
        S.insert( par( x, sol ) );
        HOW[ x ] = sol;
        x1 = x;
        x2 = y;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        p--;
        comp--;
       // for( set< par > :: iterator it = S.begin( ); it != S.end( ); it++ ) printf( "%d %d\n", it -> x, it -> val );
    }
   // while( p >= 1 ) printf( "%d %d\n", x1, x2 ), p--;
}

int main( void ) {
    load( );
    solve( );
   // system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

typedef long long llint;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x;
    llint val;
    par( int _x = 0, llint _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

llint HOW[ N ];
int comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = -1, x2 = -1;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline llint minic( const llint &A, const llint &B ) { return A > B ? A : B; }

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp < q ) { printf( "NO\n" ); return; }
    if( comp == n && p ){ printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( p ) {
        if( comp == 0 ) {
            printf( "%d %d\n", x1, x2 );
            p--;
            continue;
        }
        int x = S.begin( ) -> x;
        llint val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        llint val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, minic( val + val2 + 1, 1000000000 ) + val + val2 ) );
        HOW[ x ] = minic( val + val2 + 1, 1000000000 ) + val + val2;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        p--;
        comp--;
    }
   // while( p >= 1 ) printf( "%d %d\n", x1, x2 ), p--;
}

int main( void ) {
    load( );
    solve( );
   // system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x, val;
    par( int _x = 0, int _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

int HOW[ N ], comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = -1, x2 = -1;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp - p < q && x1 == -1 ) { printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( comp != q) {
        int x = S.begin( ) -> x;
        int val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        int val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, min( val + val2 + 1 , 1000000000 ) + val + val2 ) );
        HOW[ x ] = min( val + val2 + 1 , 1000000000 ) + val + val2;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        comp--;
        p--;
    }
    while( p >= 1 ) printf( "%d %d\n", x1, x2 ), p--;
}

int main( void ) {
    load( );
    solve( );
    //system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x, val;
    par( int _x = 0, int _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

int HOW[ N ], comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp - p !=  q ) { printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( comp != q ) {
        int x = S.begin( ) -> x;
        int val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        int val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, min( val + val2 + 1 , 1000000000 ) + val + val2 ) );
        HOW[ x ] = min( val + val2 + 1 , 1000000000 ) + val + val2;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        comp--;
    }
}

int main( void ) {
    load( );
    solve( );
    //system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x, val;
    par( int _x = 0, int _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

int HOW[ N ], comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = -1, x2 = -1;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp - p < q && x1 == -1 ) { printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( comp != q) {
        int x = S.begin( ) -> x;
        int val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        int val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, min( val + val2 + 1 , 1000000000 ) + val + val2 ) );
        HOW[ x ] = min( val + val2 + 1 , 1000000000 ) + val + val2;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        comp--;
        p--;
    }
    while( p != 0) printf( "%d %d\n", x1, x2 ), p--;
}

int main( void ) {
    load( );
    solve( );
    //system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x, val;
    par( int _x = 0, int _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

int HOW[ N ], comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = -1, x2 = -1;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp < q ) { printf( "NO\n" ); return; }
    if( comp == n && p ){ printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( comp != q ) {
        int x = S.begin( ) -> x;
        int val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        int val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, min( val + val2 + 1 , 1000000000 ) + val + val2 ) );
        HOW[ x ] = min( val + val2 + 1 , 1000000000 ) + val + val2;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        comp--;
        p--;
    }
    while( p >= 1 ) printf( "%d %d\n", x1, x2 ), p--;
}

int main( void ) {
    load( );
    solve( );
    //system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x, val;
    par( int _x = 0, int _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

int HOW[ N ], comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = 0, x2 = 0;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp - p < q ) { printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( comp != q && p ) {
        int x = S.begin( ) -> x;
        int val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        int val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, min( val + val2 + 1 , 1000000000 ) + val + val2 ) );
        HOW[ x ] = min( val + val2 + 1 , 1000000000 ) + val + val2;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        comp--;
        p--;
    }
    while( comp != q && p ) printf( "%d %d\n", x1, x2 );
}

int main( void ) {
    load( );
    solve( );
    //system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

typedef long long llint;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x;
    llint val;
    par( int _x = 0, llint _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

llint HOW[ N ];
int comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = -1, x2 = -1;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline llint minic( const llint &A, const llint &B ) { return A < B ? A : B; }

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp < q ) { printf( "NO\n" ); return; }
    if( ( comp == n && comp != q ) || ( comp == n && p )   ){ printf( "NO\n" ); return; }
   // for( set< par > :: iterator it = S.begin( ); it != S.end( ); it++ ) printf( "%d %d\n", it -> x, it -> val );

    printf( "YES\n" );
    while( p ) {
        if( comp == q ) {
            printf( "%d %d\n", x1, x2 );
            p--;
            continue;
        }
        int x = S.begin( ) -> x;
        llint val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        llint val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        llint sol = minic( val + val2 + 1, 1000000000 ) + val + val2 ;
        S.insert( par( x, sol ) );
        HOW[ x ] = sol;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        p--;
        comp--;
       // for( set< par > :: iterator it = S.begin( ); it != S.end( ); it++ ) printf( "%d %d\n", it -> x, it -> val );
    }
   // while( p >= 1 ) printf( "%d %d\n", x1, x2 ), p--;
}

int main( void ) {
    load( );
    solve( );
   // system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x, val;
    par( int _x = 0, int _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

int HOW[ N ], comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = -1, x2 = -1;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp < q ) { printf( "NO\n" ); return; }
    if( comp == n && p ){ printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( comp != q ) {
        int x = S.begin( ) -> x;
        int val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        int val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, min( val + val2 + 1 , 1000000000 ) + val + val2 ) );
        HOW[ x ] = min( val + val2 + 1 , 1000000000 ) + val + val2;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        comp--;
        p--;
    }
   // while( p >= 1 ) printf( "%d %d\n", x1, x2 ), p--;
}

int main( void ) {
    load( );
    solve( );
    //system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

typedef long long llint;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x;
    llint val;
    par( int _x = 0, llint _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

llint HOW[ N ];
int comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = -1, x2 = -1;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline llint minic( const llint &A, const llint &B ) { return A < B ? A : B; }

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp < q ) { printf( "NO\n" ); return; }
    if( comp == n && p ){ printf( "NO\n" ); return; }
   // for( set< par > :: iterator it = S.begin( ); it != S.end( ); it++ ) printf( "%d %d\n", it -> x, it -> val );

    printf( "YES\n" );
    while( p ) {
        if( comp == q ) {
            printf( "%d %d\n", x1, x2 );
            p--;
            continue;
        }
        int x = S.begin( ) -> x;
        llint val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        llint val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        llint sol = minic( val + val2 + 1, 1000000000 ) + val + val2 ;
        S.insert( par( x, sol ) );
        HOW[ x ] = sol;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        p--;
        comp--;
       // for( set< par > :: iterator it = S.begin( ); it != S.end( ); it++ ) printf( "%d %d\n", it -> x, it -> val );
    }
   // while( p >= 1 ) printf( "%d %d\n", x1, x2 ), p--;
}

int main( void ) {
    load( );
    solve( );
   // system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x, val;
    par( int _x = 0, int _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

int HOW[ N ], comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline void solve( ) {
    if( comp == q || comp - p > q ) { printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( comp != q ) {
        int x = S.begin( ) -> x;
        int val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        int val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, min( val + val2 + 1 + val + val2, 1000000000 ) ) );
        HOW[ x ] = min( val + val2 + 1 + val + val2, 1000000000 );
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        comp--;
    }
}

int main( void ) {
    load( );
    solve( );
   // system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

typedef long long llint;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x;
    llint val;
    par( int _x = 0, llint _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

llint HOW[ N ];
int comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = -1, x2 = -1;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline llint minic( const llint &A, const llint &B ) { return A < B ? A : B; }

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp < q ) { printf( "NO\n" ); return; }
    if( ( comp == n && comp == q && p ) ){ printf( "NO\n" ); return; }
    if( comp - p > q ) { printf( "NO\n" ); return; }
   // for( set< par > :: iterator it = S.begin( ); it != S.end( ); it++ ) printf( "%d %d\n", it -> x, it -> val );

    printf( "YES\n" );
    while( p ) {
        if( comp == q ) {
            printf( "%d %d\n", x1, x2 );
            p--;
            continue;
        }
        int x = S.begin( ) -> x;
        llint val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        llint val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        llint sol = minic( val + val2 + 1, 1000000000 ) + val + val2 ;
        S.insert( par( x, sol ) );
        HOW[ x ] = sol;
        x1 = x;
        x2 = y;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        p--;
        comp--;
       // for( set< par > :: iterator it = S.begin( ); it != S.end( ); it++ ) printf( "%d %d\n", it -> x, it -> val );
    }
   // while( p >= 1 ) printf( "%d %d\n", x1, x2 ), p--;
}

int main( void ) {
    load( );
    solve( );
   // system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x, val;
    par( int _x = 0, int _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

int HOW[ N ], comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline void solve( ) {
    if( comp == q || comp - p > q ) { printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( comp != q ) {
        int x = S.begin( ) -> x;
        int val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        int val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, min( val + val2 + 1 , 1000000000 ) + val + val2 ) );
        HOW[ x ] = min( val + val2 + 1 , 1000000000 ) + val + val2;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        comp--;
    }
}

int main( void ) {
    load( );
    solve( );
   // system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x, val;
    par( int _x = 0, int _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

int HOW[ N ], comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = -1, x2 = -1;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp - p < q && x1 == -1 ) { printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( comp != q && p ) {
        int x = S.begin( ) -> x;
        int val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        int val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, min( val + val2 + 1 , 1000000000 ) + val + val2 ) );
        HOW[ x ] = min( val + val2 + 1 , 1000000000 ) + val + val2;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        comp--;
        p--;
    }
    while( comp != q && p ) printf( "%d %d\n", x1, x2 );
}

int main( void ) {
    load( );
    solve( );
    //system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

typedef long long llint;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x;
    llint val;
    par( int _x = 0, llint _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

llint HOW[ N ];
int comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

int x1 = -1, x2 = -1;

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x1 = x;
        x2 = y;
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline llint minic( const llint &A, const llint &B ) { return A < B ? A : B; }

inline void solve( ) {
   // printf( "comp == %d\n", comp );
    if( comp < q ) { printf( "NO\n" ); return; }
    if( comp == n && p ){ printf( "NO\n" ); return; }
   // for( set< par > :: iterator it = S.begin( ); it != S.end( ); it++ ) printf( "%d %d\n", it -> x, it -> val );

    printf( "YES\n" );
    while( p ) {
        if( comp == 0 ) {
            printf( "%d %d\n", x1, x2 );
            p--;
            continue;
        }
        int x = S.begin( ) -> x;
        llint val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        llint val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        llint sol = minic( val + val2 + 1, 1000000000 ) + val + val2 ;
        S.insert( par( x, sol ) );
        HOW[ x ] = sol;
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        p--;
        comp--;
       // for( set< par > :: iterator it = S.begin( ); it != S.end( ); it++ ) printf( "%d %d\n", it -> x, it -> val );
    }
   // while( p >= 1 ) printf( "%d %d\n", x1, x2 ), p--;
}

int main( void ) {
    load( );
    solve( );
   // system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x, val;
    par( int _x = 0, int _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

int HOW[ N ], comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline void solve( ) {
    if( comp == q || comp - p > q ) { printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( comp != q ) {
        int x = S.begin( ) -> x;
        int val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        int val2 = S.begin( ) -> val;
        //printf( "dada %d %d\n", val, val2 );
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, min( val + val2 + 1 + HOW[ x ] + HOW[ y ], 1000000000 ) ) );
        HOW[ x ] = min( val + val2 + 1 + HOW[ x ] + HOW[ y ], 1000000000 );
       // printf( "%d\n", HOW[ x ] );
      //  system( "pause" );
        comp--;
    }
}

int main( void ) {
    load( );
    solve( );
  //  system( "pause" );
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

const int N = 100100;

int parent[ N ];

int n, q, m, p;

vector< int > graf[ N ];

struct par {
    int x, val;
    par( int _x = 0, int _val = 0 ) {
        x = _x;
        val = _val;
    }
    inline bool friend operator <( const par &A, const par &B ) {
        if( A.val != B.val ) return A.val < B.val;
        return A.x < B.x;
    }
};

set< par > S;

int HOW[ N ], comp;

int find( int x ) { return x == parent[ x ] ? x : parent[ x ] = find( parent[ x ] ); }

inline void load( ) {
    scanf( "%d %d %d %d", &n, &m, &p, &q );
    for( int i = 1; i <= n; i++ ) S.insert( par( i, 0 ) ), parent[ i ] = i;
    comp = n;
    for( int i = 0; i < m; i++ ) {
        int x, y, val;
        scanf( "%d %d %d", &x, &y, &val );
        x = find( x );
        y = find( y );
        if( x != y ) {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.erase( S.find( par( y, HOW[ y ] ) ) );
            parent[ y ] = x;
            S.insert( par( x, HOW[ x ] + HOW[ y ] + val ) );
            HOW[ x ] = HOW[ x ] + HOW[ y ] + val;
            comp--;
        }
        else {
            S.erase( S.find( par( x, HOW[ x ] ) ) );
            S.insert( par( x, HOW[ x ] + val ) );
            HOW[ x ] += val;
        }
    }
}

inline void solve( ) {
    if( comp == q || comp - p > q ) { printf( "NO\n" ); return; }

    printf( "YES\n" );
    while( comp != q ) {
        int x = S.begin( ) -> x;
        int val = S.begin( ) -> val;
        S.erase( S.begin( ) );
        int y = S.begin( ) -> x;
        int val2 = S.begin( ) -> val;
        printf( "%d %d\n", x, y );
        parent[ y ] = x;
        S.erase( S.begin( ) );
        S.insert( par( x, min( HOW[ x ] + HOW[ y ] + 1, 1000000000 ) ) );
        HOW[ x ] = min( HOW[ x ] + HOW[ y ] + 1, 1000000000 );
        comp--;
    }
}

int main( void ) {
    load( );
    solve( );
    //system( "pause" );
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, int> ii;
const int N = 100010;
int n, m, k, q, a, b, c, p[N];
ll sz[N], len;

priority_queue<ii, vector<ii>, greater<ii> > qu;
vector<ii> v;
int node[N];

int find(int x) {
	if(x == p[x]) return x;
	return p[x] = find(p[x]);
}

int main(int argc, char **argv) {
#ifndef ONLINE_JUDGE
	freopen("a.in", "r", stdin);
#endif
	scanf("%d%d%d%d", &n, &m, &k, &q);
	int now = n;
	for(int i=0 ; i<=n ; ++i)
		p[i] = i;
	while(m--) {
		scanf("%d%d%d", &a, &b, &c);
		a = find(a), b = find(b);
		if(a != b) {
			sz[b] += sz[a] + c;
			p[a] = b;
			--now;
		} else {
			sz[a] += c;
		}
	}
	for(int i=1 ; i<=n ; ++i)
		v.push_back(ii(sz[find(i)], find(i)));
	sort(v.begin(), v.end());
	v.resize(unique(v.begin(), v.end()) - v.begin());
	for(int i=0 ; i<(int)v.size() ; ++i)
		qu.push(ii(v[i].first, v[i].second));
	for(int i=1 ; i<=n ; ++i)
		node[find(i)] = i;
	v.clear();
	while(now > q && k>0) {
		a = qu.top().second;
		qu.pop();
		b = qu.top().second;
		qu.pop();
		a = find(a), b = find(b);
		len = sz[a] + sz[b] + 1;
		len = min(len, 1000000000LL);
		sz[b] += sz[a] + len;
		a = find(a);
		b = find(b);
		v.push_back(ii(a, b));
		p[a] = b;
		a = find(a);
		qu.push(ii(sz[b], b));
		--now;
		--k;

	}
	if(now != q) {
		return puts("NO"), 0;
	}
	if(k > 0) {
		for(int i=1 ; i<=n ; ++i)
			if(find(i) != i) {
				while(k > 0) {
					v.push_back(ii(i, find(i)));
					--k;
				}
				break;
			}
	}
	if(k != 0 || now != q) puts("NO");
	else {
		puts("YES");
		for(int i=0 ; i<(int)v.size() ; ++i) {
			printf("%lld %d\n", v[i].first, v[i].second);
		}
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> ii;
const int N = 100010;
int n, m, k, q, a, b, c, p[N];
ll sz[N], len;
priority_queue<ii, vector<ii>, greater<ii> > qu;
vector<ii> v;
int node[N];

int find(int x) {
	if(x == p[x]) return x;
	return p[x] = find(p[x]);
}

int main(int argc, char **argv) {
#ifndef ONLINE_JUDGE
	freopen("a.in", "r", stdin);
#endif
	scanf("%d%d%d%d", &n, &m, &k, &q);
	int now = n;
	for(int i=0 ; i<=n ; ++i)
		p[i] = i;
	while(m--) {
		scanf("%d%d%d", &a, &b, &c);
		a = find(a), b = find(b);
		if(a != b) {
			sz[b] += sz[a] + c;
			p[a] = b;
			--now;
		} else {
			sz[a] += c;
		}
	}
	for(int i=1 ; i<=n ; ++i)
		v.push_back(ii(sz[find(i)], find(i)));
	sort(v.begin(), v.end());
	v.resize(unique(v.begin(), v.end()) - v.begin());
	for(int i=0 ; i<(int)v.size() ; ++i)
		qu.push(v[i]);
	for(int i=1 ; i<=n ; ++i)
		node[find(i)] = i;
	v.clear();
	while(now > q) {
		a = qu.top().second;
		qu.pop();
		b = qu.top().second;
		len = sz[a] + sz[b] + 1;
		len = min(len, 1000000000LL);
		sz[b] += sz[a] + len;
		a = find(a);
		b = find(b);
		v.push_back(ii(a, b));
		p[a] = b;
		qu.push(ii(sz[b], b));
		--now;
		--k;

	}
	if(k > 0) {
		for(int i=1 ; i<=n ; ++i)
			if(find(i) != i) {
				while(p > 0) {
					v.push_back(ii(i, find(i)));
					--k;
				}
				break;
			}
	}
	if(k > 0 || now != q) puts("NO");
	else {
		puts("YES");
		for(int i=0 ; i<(int)v.size() ; ++i) {
			printf("%d %d\n", v[i].first, v[i].second);
		}
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> ii;
const int N = 100010;
int n, m, k, q, a, b, c, p[N];
ll sz[N], len;
priority_queue<ii, vector<ii>, greater<ii> > qu;
vector<ii> v;
int node[N];

int find(int x) {
	if(x == p[x]) return x;
	return p[x] = find(p[x]);
}

int main(int argc, char **argv) {
#ifndef ONLINE_JUDGE
	freopen("a.in", "r", stdin);
#endif
	scanf("%d%d%d%d", &n, &m, &k, &q);
	int now = n;
	for(int i=0 ; i<=n ; ++i)
		p[i] = i;
	while(m--) {
		scanf("%d%d%d", &a, &b, &c);
		a = find(a), b = find(b);
		if(a != b) {
			sz[b] += sz[a] + c;
			p[a] = b;
			--now;
		} else {
			sz[a] += c;
		}
	}
	for(int i=1 ; i<=n ; ++i)
		v.push_back(ii(sz[find(i)], find(i)));
	sort(v.begin(), v.end());
	v.resize(unique(v.begin(), v.end()) - v.begin());
	for(int i=0 ; i<(int)v.size() ; ++i)
		qu.push(v[i]);
	for(int i=1 ; i<=n ; ++i)
		node[find(i)] = i;
	v.clear();
	while(now > q && k>0) {
		a = qu.top().second;
		qu.pop();
		b = qu.top().second;
		a = find(a), b = find(b);
		len = sz[a] + sz[b] + 1;
		len = min(len, 1000000000LL);
		sz[b] += sz[a] + len;
		a = find(a);
		b = find(b);
		v.push_back(ii(a, b));
		p[a] = b;
		a = find(a);
		qu.push(ii(sz[b], b));
		--now;
		--k;

	}
	if(now != q) {
		return puts("NO"), 0;
	}
	if(k > 0) {
		for(int i=1 ; i<=n ; ++i)
			if(find(i) != i) {
				while(k > 0) {
					v.push_back(ii(i, find(i)));
					--k;
				}
				break;
			}
	}
	if(k > 0 || now != q) puts("NO");
	else {
		puts("YES");
		for(int i=0 ; i<(int)v.size() ; ++i) {
			printf("%d %d\n", v[i].first, v[i].second);
		}
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> ii;
const int N = 100010;
int n, m, k, q, a, b, c, p[N];
ll sz[N], len;
priority_queue<ii, vector<ii>, greater<ii> > qu;
vector<ii> v;
int node[N];

int find(int x) {
	if(x == p[x]) return x;
	return p[x] = find(p[x]);
}

int main(int argc, char **argv) {
#ifndef ONLINE_JUDGE
	freopen("a.in", "r", stdin);
#endif
	scanf("%d%d%d%d", &n, &m, &k, &q);
	int now = n;
	for(int i=0 ; i<=n ; ++i)
		p[i] = i;
	while(m--) {
		scanf("%d%d%d", &a, &b, &c);
		a = find(a), b = find(b);
		if(a != b) {
			sz[b] += sz[a] + c;
			p[a] = b;
			--now;
		} else {
			sz[a] += c;
		}
	}
	for(int i=1 ; i<=n ; ++i)
		v.push_back(ii(sz[find(i)], find(i)));
	sort(v.begin(), v.end());
	v.resize(unique(v.begin(), v.end()) - v.begin());
	for(int i=0 ; i<(int)v.size() ; ++i)
		qu.push(v[i]);
	for(int i=1 ; i<=n ; ++i)
		node[find(i)] = i;
	v.clear();
	while(now > q && k>0) {
		a = qu.top().second;
		qu.pop();
		b = qu.top().second;
		a = find(a), b = find(b);
		len = sz[a] + sz[b] + 1;
		len = min(len, 1000000000LL);
		sz[b] += sz[a] + len;
		a = find(a);
		b = find(b);
		v.push_back(ii(a, b));
		p[a] = b;
		a = find(a);
		qu.push(ii(sz[b], b));
		--now;
		--k;

	}
	if(now != q) {
		return puts("NO"), 0;
	}
	if(k > 0) {
		for(int i=1 ; i<=n ; ++i)
			if(find(i) != i) {
				while(k > 0) {
					v.push_back(ii(i, find(i)));
					--k;
				}
				break;
			}
	}
	if(k != 0 || now != q) puts("NO");
	else {
		puts("YES");
		for(int i=0 ; i<(int)v.size() ; ++i) {
			printf("%d %d\n", v[i].first, v[i].second);
		}
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> ii;
const int N = 100010;
ll n, m, k, q, a, b, c, p[N];
ll sz[N], len;

priority_queue<ii, vector<ii>, greater<ii> > qu;
vector<ii> v;
ll node[N];

ll find(ll x) {
	if(x == p[x]) return x;
	return p[x] = find(p[x]);
}

int main(int argc, char **argv) {
#ifndef ONLINE_JUDGE
	freopen("a.in", "r", stdin);
#endif
	scanf("%lld%lld%lld%lld", &n, &m, &k, &q);
	ll now = n;
	for(int i=0 ; i<=n ; ++i)
		p[i] = i;
	while(m--) {
		scanf("%lld%lld%lld", &a, &b, &c);
		a = find(a), b = find(b);
		if(a != b) {
			sz[b] += sz[a] + c;
			p[a] = b;
			--now;
		} else {
			sz[a] += c;
		}
	}
	for(int i=1 ; i<=n ; ++i)
		v.push_back(ii(sz[find(i)], find(i)));
	sort(v.begin(), v.end());
	v.resize(unique(v.begin(), v.end()) - v.begin());
	for(int i=0 ; i<(int)v.size() ; ++i)
		qu.push(ii(v[i].first, v[i].second));
	for(int i=1 ; i<=n ; ++i)
		node[find(i)] = i;
	v.clear();
	while(now > q && k>0) {
		a = qu.top().second;
		qu.pop();
		b = qu.top().second;
		qu.pop();
		a = find(a), b = find(b);
		len = sz[a] + sz[b] + 1;
		len = min(len, 1000000000LL);
		sz[b] += sz[a] + len;
		a = find(a);
		b = find(b);
		v.push_back(ii(a, b));
		p[a] = b;
		a = find(a);
		qu.push(ii(sz[b], b));
		--now;
		--k;

	}
	if(now != q) {
		return puts("NO"), 0;
	}
	if(k > 0) {
		for(int i=1 ; i<=n ; ++i)
			if(find(i) != i) {
				while(k > 0) {
					v.push_back(ii(i, find(i)));
					--k;
				}
				break;
			}
	}
	if(k != 0 || now != q) puts("NO");
	else {
		puts("YES");
		for(int i=0 ; i<(int)v.size() ; ++i) {
			printf("%lld %lld\n", v[i].first, v[i].second);
		}
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> ii;
const int N = 100010;
int n, m, k, q, a, b, c, p[N];
ll sz[N], len;

priority_queue<ii, vector<ii>, greater<ii> > qu;
vector<ii> v;
int node[N];

int find(int x) {
	if(x == p[x]) return x;
	return p[x] = find(p[x]);
}

int main(int argc, char **argv) {
#ifndef ONLINE_JUDGE
	freopen("a.in", "r", stdin);
#endif
	scanf("%d%d%d%d", &n, &m, &k, &q);
	int now = n;
	for(int i=0 ; i<=n ; ++i)
		p[i] = i;
	while(m--) {
		scanf("%d%d%d", &a, &b, &c);
		a = find(a), b = find(b);
		if(a != b) {
			sz[b] += sz[a] + c;
			p[a] = b;
			--now;
		} else {
			sz[a] += c;
		}
	}
	for(int i=1 ; i<=n ; ++i)
		v.push_back(ii(sz[find(i)], find(i)));
	sort(v.begin(), v.end());
	v.resize(unique(v.begin(), v.end()) - v.begin());
	for(int i=0 ; i<(int)v.size() ; ++i)
		qu.push(ii(v[i].first, v[i].second));
	for(int i=1 ; i<=n ; ++i)
		node[find(i)] = i;
	v.clear();
	while(now > q && k>0) {
		a = qu.top().second;
		qu.pop();
		b = qu.top().second;
		a = find(a), b = find(b);
		len = sz[a] + sz[b] + 1;
		len = min(len, 1000000000LL);
		sz[b] += sz[a] + len;
		a = find(a);
		b = find(b);
		v.push_back(ii(a, b));
		p[a] = b;
		a = find(a);
		qu.push(ii(sz[b], b));
		--now;
		--k;

	}
	if(now != q) {
		return puts("NO"), 0;
	}
	if(k > 0) {
		for(int i=1 ; i<=n ; ++i)
			if(find(i) != i) {
				while(k > 0) {
					v.push_back(ii(i, find(i)));
					--k;
				}
				break;
			}
	}
	if(k != 0 || now != q) puts("NO");
	else {
		puts("YES");
		for(int i=0 ; i<(int)v.size() ; ++i) {
			printf("%lld %lld\n", v[i].first, v[i].second);
		}
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, int> ii;
const int N = 100010;
int n, m, k, q, a, b, c, p[N];
ll sz[N], len;
priority_queue<ii, vector<ii>, greater<ii> > qu;
vector<ii> v;
int node[N];

int find(int x) {
	if(x == p[x]) return x;
	return p[x] = find(p[x]);
}

int main(int argc, char **argv) {
#ifndef ONLINE_JUDGE
	freopen("a.in", "r", stdin);
#endif
	scanf("%d%d%d%d", &n, &m, &k, &q);
	int now = n;
	for(int i=0 ; i<=n ; ++i)
		p[i] = i;
	while(m--) {
		scanf("%d%d%d", &a, &b, &c);
		a = find(a), b = find(b);
		if(a != b) {
			sz[b] += sz[a] + c;
			p[a] = b;
			--now;
		} else {
			sz[a] += c;
		}
	}
	for(int i=1 ; i<=n ; ++i)
		v.push_back(ii(sz[find(i)], find(i)));
	sort(v.begin(), v.end());
	v.resize(unique(v.begin(), v.end()) - v.begin());
	for(int i=0 ; i<(int)v.size() ; ++i)
		qu.push(v[i]);
	for(int i=1 ; i<=n ; ++i)
		node[find(i)] = i;
	v.clear();
	while(now > q && k>0) {
		a = qu.top().second;
		qu.pop();
		b = qu.top().second;
		a = find(a), b = find(b);
		len = sz[a] + sz[b] + 1;
		len = min(len, 1000000000LL);
		sz[b] += sz[a] + len;
		a = find(a);
		b = find(b);
		v.push_back(ii(a, b));
		p[a] = b;
		a = find(a);
		qu.push(ii(sz[b], b));
		--now;
		--k;

	}
	if(now != q) {
		return puts("NO"), 0;
	}
	if(k > 0) {
		for(int i=1 ; i<=n ; ++i)
			if(find(i) != i) {
				while(k > 0) {
					v.push_back(ii(i, find(i)));
					--k;
				}
				break;
			}
	}
	if(k != 0 || now != q) puts("NO");
	else {
		puts("YES");
		for(int i=0 ; i<(int)v.size() ; ++i) {
			printf("%d %d\n", v[i].first, v[i].second);
		}
	}
	return 0;
}


#include <cstring>
#include <queue>
using namespace std;
#include <stdio.h>

#define N 100005
#define INF 1000000000

int adj[N];
int rn[N];
int first;
struct Road
{
	int neighbour;
	int len;
	int next;
}road[N * 2];

struct Region
{
	int pcity;
	int sum;
	bool operator <(const Region &r) const
	{
		return sum > r.sum;
	}
};

int findExtra;
int extra[2];

void Read(int n, int m, int p, int q)
{
	int x, y, l;
	first = 0;
	memset(&adj[1], -1, n*sizeof(int));
	findExtra = 0;

	for (int i=0; i<m; ++i) {
		scanf("%d%d%d", &x, &y, &l);
		road[first].neighbour = y;
		road[first].len = l;
		road[first].next = adj[x];
		adj[x] = first++;
		road[first].neighbour = x;
		road[first].len = l;
		road[first].next = adj[y];
		adj[y] = first++;
		if (0 == findExtra) {
			findExtra = 1;
			extra[0] = x; extra[1] = y;
		}
	}
}

void visit(int sta, int arn, Region &reg) /* start number, assigned region number */
{
	rn[sta] = arn;
	int ptr = adj[sta];

	while (ptr != -1) {
		if (rn[road[ptr].neighbour] == -1) {
			reg.sum = min(INF, reg.sum + road[ptr].len);
			visit(road[ptr].neighbour, arn, reg);
		}

		ptr = road[ptr].next;
	}
}

void Solve(int n, int m, int p, int q)
{
	memset(&rn[1], -1, n*sizeof(int));
	first = -1;
	priority_queue<Region> pq;

	for (int i=1; i<=n; ++i) {
		if (rn[i] == -1) {
			Region region = {i, 0LL};
			++first;
			visit(i, first, region);
			pq.push(region);
		}
	}

	int regionNum = first + 1;

	if (regionNum < q || regionNum > q + p || (regionNum == q && m == 0 && p > 0)) {
		printf("NO\n");
		return ;
	}

	/*if (n == 98743 && m == 98000 && p == 89000 && q == 1) {
		printf("%d\n", regionNum);
	}*/
	printf("YES\n");

	while (regionNum > q && p > 0) {
		Region r1 = pq.top();
		pq.pop();
		Region r2 = pq.top();
		pq.pop();

		if (findExtra == 0) {
			extra[0] = r1.pcity;
			extra[1] = r2.pcity;
			findExtra = 1;
		}

		printf("%d %d\n", r1.pcity, r2.pcity);
		if (n == 98743 && m == 98000 && q == 1) {
			printf("xx = %d %d\n", r1.sum, r2.sum);
		}
		int tmp = min(INF, r1.sum + r2.sum + 1);
		r1.sum = min(INF, min(INF, r1.sum + tmp) + r2.sum);
		pq.push(r1);
		--regionNum; --p;
	}

	for (int i=0; i<p; ++i) { printf("%d %d\n", extra[0], extra[1]); }
}

int main()
{
	int n, m, p, q;

	while (EOF != scanf("%d%d%d%d", &n, &m, &p, &q)) {
		Read(n, m, p, q);
		Solve(n, m, p, q);
	}

	return 0;
}


#include <iostream>
#include <cstring>
#include <queue>
using namespace std;

#define N 100005

int adj[N];
int rn[N];
int newRoad[N][2];
int first;
struct Road
{
	int neighbour;
	int len;
	int next;
}road[N * 2];

struct Region
{
	int pcity;
	long long sum;
	bool operator <(const Region &r) const
	{
		return sum > r.sum;
	}
};

int findExtra;
int extra[2];

void Read(int n, int m, int p, int q)
{
	int x, y, l;
	first = 0;
	memset(&adj[1], -1, n*sizeof(int));
	findExtra = 0;

	for (int i=0; i<m; ++i) {
		cin >> x >> y >> l;
		road[first].neighbour = y;
		road[first].len = l;
		road[first].next = adj[x];
		adj[x] = first++;
		road[first].neighbour = x;
		road[first].len = l;
		road[first].next = adj[y];
		adj[y] = first++;
		if (0 == findExtra) {
			findExtra = 1;
			extra[0] = x; extra[1] = y;
		}
	}
}

void visit(int sta, int arn, Region &reg) /* start number, assigned region number */
{
	rn[sta] = arn;
	int ptr = adj[sta];

	while (ptr != -1) {
		if (rn[road[ptr].neighbour] == -1) {
			reg.sum += road[ptr].len;
			visit(road[ptr].neighbour, arn, reg);
		}

		ptr = road[ptr].next;
	}
}

void Solve(int n, int m, int p, int q)
{
	memset(&rn[1], -1, n*sizeof(int));
	first = -1;
	priority_queue<Region> pq;

	for (int i=1; i<=n; ++i) {
		if (rn[i] == -1) {
			Region region = {i, 0LL};
			++first;
			visit(i, first, region);
			pq.push(region);
		}
	}

	int regionNum = first + 1;
	int newRoadNum = 0;

	while (regionNum > q && p > 0) {
		Region r1 = pq.top();
		pq.pop();
		Region r2 = pq.top();
		pq.pop();

		if (findExtra == 0) {
			extra[0] = r1.pcity;
			extra[1] = r2.pcity;
			findExtra = 1;
		}

		newRoad[newRoadNum][0] = r1.pcity;
		newRoad[newRoadNum++][1] = r2.pcity;
		r1.sum += min(1000000000LL, r1.sum + r2.sum + 1);
		pq.push(r1);
		--regionNum; --p;
	}

	if (regionNum != q || (p > 0 && findExtra == 0)) {
		cout << "NO" << endl;
	} else {
		cout << "YES" << endl;
		for (int i=0; i<newRoadNum; ++i) { cout << newRoad[i][0] << newRoad[i][1] << endl; }
		for (int i=0; i<p; ++i) { cout << extra[0] << extra[1] << endl; }
	}
}

int main()
{
	int n, m, p, q;

	while (cin >> n >> m >> p >> q) {
		Read(n, m, p, q);
		Solve(n, m, p, q);
	}

	return 0;
}


#include <cstring>
#include <queue>
using namespace std;
#include <stdio.h>

#define N 100005
#define INF 1000000000

int adj[N];
int rn[N];
int first;
struct Road
{
	int neighbour;
	int len;
	int next;
}road[N * 2];

struct Region
{
	int pcity;
	int sum;
	bool operator <(const Region &r) const
	{
		return sum > r.sum;
	}
};

int findExtra;
int extra[2];

void Read(int n, int m, int p, int q)
{
	int x, y, l;
	first = 0;
	memset(&adj[1], -1, n*sizeof(int));
	findExtra = 0;

	for (int i=0; i<m; ++i) {
		scanf("%d%d%d", &x, &y, &l);
		road[first].neighbour = y;
		road[first].len = l;
		road[first].next = adj[x];
		adj[x] = first++;
		road[first].neighbour = x;
		road[first].len = l;
		road[first].next = adj[y];
		adj[y] = first++;
		if (0 == findExtra) {
			findExtra = 1;
			extra[0] = x; extra[1] = y;
		}
	}
}

void visit(int sta, int arn, Region &reg) /* start number, assigned region number */
{
	rn[sta] = arn;
	int ptr = adj[sta];

	while (ptr != -1) {
		if (rn[road[ptr].neighbour] == -1) {
			reg.sum += road[ptr].len;
			visit(road[ptr].neighbour, arn, reg);
		}

		ptr = road[ptr].next;
	}
}

void Solve(int n, int m, int p, int q)
{
	memset(&rn[1], -1, n*sizeof(int));
	first = -1;
	priority_queue<Region> pq;

	for (int i=1; i<=n; ++i) {
		if (rn[i] == -1) {
			Region region = {i, 0LL};
			++first;
			visit(i, first, region);
			pq.push(region);
		}
	}

	int regionNum = first + 1;

	if (regionNum < q || (regionNum == q && m == 0 && p > 0)) {
		printf("NO\n");
		return ;
	}

	printf("YES\n");

	while (regionNum > q && p > 0) {
		Region r1 = pq.top();
		pq.pop();
		Region r2 = pq.top();
		pq.pop();

		if (findExtra == 0) {
			extra[0] = r1.pcity;
			extra[1] = r2.pcity;
			findExtra = 1;
		}

		printf("%d %d\n", r1.pcity, r2.pcity);
		int tmp = min(INF, r1.sum + r2.sum + 1);
		r1.sum = min(INF, min(INF, r1.sum + tmp) + INF);
		pq.push(r1);
		--regionNum; --p;
	}

	for (int i=0; i<p; ++i) { printf("%d %d\n", extra[0], extra[1]); }
}

int main()
{
	int n, m, p, q;

	while (EOF != scanf("%d%d%d%d", &n, &m, &p, &q)) {
		Read(n, m, p, q);
		Solve(n, m, p, q);
	}

	return 0;
}


#include <iostream>
#include <queue>
using namespace std;

#define N 100005

int adj[N];
int rn[N];
int newRoad[N][2];
int first;
struct Road
{
	int neighbour;
	int len;
	int next;
}road[N * 2];

struct Region
{
	int pcity;
	long long sum;
	bool operator <(const Region &r) const
	{
		return sum > r.sum;
	}
};

int findExtra;
int extra[2];

void Read(int n, int m, int p, int q)
{
	int x, y, l;
	first = 0;
	memset(&adj[1], -1, n*sizeof(int));
	findExtra = 0;

	for (int i=0; i<m; ++i) {
		cin >> x >> y >> l;
		road[first].neighbour = y;
		road[first].len = l;
		road[first].next = adj[x];
		adj[x] = first++;
		road[first].neighbour = x;
		road[first].len = l;
		road[first].next = adj[y];
		adj[y] = first++;
		if (0 == findExtra) {
			findExtra = 1;
			extra[0] = x; extra[1] = y;
		}
	}
}

void visit(int sta, int arn, Region &reg) /* start number, assigned region number */
{
	rn[sta] = arn;
	int ptr = adj[sta];

	while (ptr != -1) {
		if (rn[road[ptr].neighbour] == -1) {
			reg.sum += road[ptr].len;
			visit(road[ptr].neighbour, arn, reg);
		}

		ptr = road[ptr].next;
	}
}

void Solve(int n, int m, int p, int q)
{
	memset(&rn[1], -1, n*sizeof(int));
	first = -1;
	priority_queue<Region> pq;

	for (int i=1; i<=n; ++i) {
		if (rn[i] == -1) {
			Region region = {i, 0LL};
			++first;
			visit(i, first, region);
			pq.push(region);
		}
	}

	int regionNum = first + 1;
	int newRoadNum = 0;

	while (regionNum > q && p > 0) {
		Region r1 = pq.top();
		pq.pop();
		Region r2 = pq.top();
		pq.pop();

		if (findExtra == 0) {
			extra[0] = r1.pcity;
			extra[1] = r2.pcity;
			findExtra = 1;
		}

		newRoad[newRoadNum][0] = r1.pcity;
		newRoad[newRoadNum++][1] = r2.pcity;
		r1.sum += min(1000000000LL, r1.sum + r2.sum + 1);
		pq.push(r1);
		--regionNum; --p;
	}

	if (regionNum != q || (p > 0 && findExtra == 0)) {
		printf("NO\n");
	} else {
		printf("YES\n");
		for (int i=0; i<newRoadNum; ++i) { printf("%d %d\n", newRoad[i][0], newRoad[i][1]); }
		for (int i=0; i<p; ++i) { printf("%d %d\n", extra[0], extra[1]); }
	}
}

int main()
{
	int n, m, p, q;

	while (cin >> n >> m >> p >> q) {
		Read(n, m, p, q);
		Solve(n, m, p, q);
	}

	return 0;
}


#include <cstring>
#include <queue>
using namespace std;
#include <stdio.h>

#define N 100005
#define INF 1000000000

int adj[N];
int rn[N];
int first;
struct Road
{
	int neighbour;
	int len;
	int next;
}road[N * 2];

struct Region
{
	int pcity;
	int sum;
	bool operator <(const Region &r) const
	{
		return sum > r.sum;
	}
};

int findExtra;
int extra[2];

void Read(int n, int m, int p, int q)
{
	int x, y, l;
	first = 0;
	memset(&adj[1], -1, n*sizeof(int));
	findExtra = 0;

	for (int i=0; i<m; ++i) {
		scanf("%d%d%d", &x, &y, &l);
		road[first].neighbour = y;
		road[first].len = l;
		road[first].next = adj[x];
		adj[x] = first++;
		road[first].neighbour = x;
		road[first].len = l;
		road[first].next = adj[y];
		adj[y] = first++;
		if (0 == findExtra) {
			findExtra = 1;
			extra[0] = x; extra[1] = y;
		}
	}
}

void visit(int sta, int arn, Region &reg) /* start number, assigned region number */
{
	rn[sta] = arn;
	int ptr = adj[sta];

	while (ptr != -1) {
		if (rn[road[ptr].neighbour] == -1) {
			reg.sum = min(INF, reg.sum + road[ptr].len);
			visit(road[ptr].neighbour, arn, reg);
		}

		ptr = road[ptr].next;
	}
}

void Solve(int n, int m, int p, int q)
{
	memset(&rn[1], -1, n*sizeof(int));
	first = -1;
	priority_queue<Region> pq;

	for (int i=1; i<=n; ++i) {
		if (rn[i] == -1) {
			Region region = {i, 0LL};
			++first;
			visit(i, first, region);
			pq.push(region);
		}
	}

	int regionNum = first + 1;

	if (regionNum < q || regionNum > q + p || (regionNum == q && m == 0 && p > 0)) {
		printf("NO\n");
		return ;
	}

	printf("YES\n");

	while (regionNum > q && p > 0) {
		Region r1 = pq.top();
		pq.pop();
		Region r2 = pq.top();
		pq.pop();

		if (findExtra == 0) {
			extra[0] = r1.pcity;
			extra[1] = r2.pcity;
			findExtra = 1;
		}

		printf("%d %d\n", r1.pcity, r2.pcity);
		int tmp = min(INF, r1.sum + r2.sum + 1);
		r1.sum = min(INF, min(INF, r1.sum + tmp) + r2.sum);
		pq.push(r1);
		--regionNum; --p;
	}

	for (int i=0; i<p; ++i) { printf("%d %d\n", extra[0], extra[1]); }
}

int main()
{
	int n, m, p, q;

	while (EOF != scanf("%d%d%d%d", &n, &m, &p, &q)) {
		Read(n, m, p, q);
		Solve(n, m, p, q);
	}

	return 0;
}


#include <iostream>
#include <cstring>
#include <queue>
using namespace std;

#define N 100005

int adj[N];
int rn[N];
int newRoad[N][2];
int first;
struct Road
{
	int neighbour;
	int len;
	int next;
}road[N * 2];

struct Region
{
	int pcity;
	long long sum;
	bool operator <(const Region &r) const
	{
		return sum > r.sum;
	}
};

int findExtra;
int extra[2];

void Read(int n, int m, int p, int q)
{
	int x, y, l;
	first = 0;
	memset(&adj[1], -1, n*sizeof(int));
	findExtra = 0;

	for (int i=0; i<m; ++i) {
		cin >> x >> y >> l;
		road[first].neighbour = y;
		road[first].len = l;
		road[first].next = adj[x];
		adj[x] = first++;
		road[first].neighbour = x;
		road[first].len = l;
		road[first].next = adj[y];
		adj[y] = first++;
		if (0 == findExtra) {
			findExtra = 1;
			extra[0] = x; extra[1] = y;
		}
	}
}

void visit(int sta, int arn, Region &reg) /* start number, assigned region number */
{
	rn[sta] = arn;
	int ptr = adj[sta];

	while (ptr != -1) {
		if (rn[road[ptr].neighbour] == -1) {
			reg.sum += road[ptr].len;
			visit(road[ptr].neighbour, arn, reg);
		}

		ptr = road[ptr].next;
	}
}

void Solve(int n, int m, int p, int q)
{
	memset(&rn[1], -1, n*sizeof(int));
	first = -1;
	priority_queue<Region> pq;

	for (int i=1; i<=n; ++i) {
		if (rn[i] == -1) {
			Region region = {i, 0LL};
			++first;
			visit(i, first, region);
			pq.push(region);
		}
	}

	int regionNum = first + 1;
	int newRoadNum = 0;

	while (regionNum > q && p > 0) {
		Region r1 = pq.top();
		pq.pop();
		Region r2 = pq.top();
		pq.pop();

		if (findExtra == 0) {
			extra[0] = r1.pcity;
			extra[1] = r2.pcity;
			findExtra = 1;
		}

		newRoad[newRoadNum][0] = r1.pcity;
		newRoad[newRoadNum++][1] = r2.pcity;
		r1.sum += min(1000000000LL, r1.sum + r2.sum + 1);
		pq.push(r1);
		--regionNum; --p;
	}

	if (regionNum != q || (p > 0 && findExtra == 0)) {
		cout << "NO" << endl;
	} else {
		cout << "YES" << endl;
		for (int i=0; i<newRoadNum; ++i) { cout << newRoad[i][0] << ' ' << newRoad[i][1] << endl; }
		for (int i=0; i<p; ++i) { cout << extra[0] << ' ' << extra[1] << endl; }
	}
}

int main()
{
	int n, m, p, q;

	while (cin >> n >> m >> p >> q) {
		Read(n, m, p, q);
		Solve(n, m, p, q);
	}

	return 0;
}