#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#define inf 1000000007

using namespace std;

int cc;
vector <pair<int,int> > adj[111111];
int vis[111111], r[111111], o[1111111];
int len[111111];

void dfs(int u)
{
    vis[u] = 1;
    for(int i=0;i<adj[u].size();i++)
    {
        len[cc] = min(1000000000,len[cc]+adj[u][i].second);
        int v = adj[u][i].first;
        if(!vis[v])
        {
            o[cc] = v;
            dfs(v);
        }
    }
}

int main()
{
    int n, m, p, q;
    cc = 0;
    cin >> n >> m >> p >> q;
    for(int i=0;i<m;i++)
    {
        int a, b, l;
        cin >> a >> b >> l;
        adj[a].push_back(make_pair(b,l));
        adj[b].push_back(make_pair(a,l));
    }
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            dfs(i);
            r[cc] = i;
            len[cc++] /= 2;
        }
    }
    priority_queue <pair<int,int> >  pq;
    vector <pair<int,int> > v;
    for(int i=0;i<cc;i++) pq.push(make_pair(-len[i],i));
    while(q < pq.size())
    {
        if(p == 0) break;
        pair <int,int> x, y, z;
        x = pq.top(); pq.pop();
        y = pq.top(); pq.pop();
        r[cc] = r[x.second];
        o[cc] = r[y.second];
        z.first = max(-1000000000, x.first + y.first - 1);
        z.second = cc++;
        pq.push(z);
        v.push_back(make_pair(r[x.second],r[y.second]));
        p--;
    }
    if(pq.size() != q) cout << "NO" << endl;
    else
    {
        if(p)
        {
            pair <int,int> x;
            while(!pq.empty() && o[pq.top().second] == 0) pq.pop();
            if(!pq.empty())
            {
                x = pq.top(); pq.pop();
                while(p)
                {
                    v.push_back(make_pair(r[x.second],o[x.second]));
                    p--;
                }
            }
        }
        if(p) cout << "NO" << endl;
        else
        {
            cout << "YES" << endl;
            for(int i=0;i<v.size();i++) cout << v[i].first << " " << v[i].second << endl;
        }
    }
    return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#define inf 1000000007

using namespace std;

int cc;
vector <pair<int,int> > adj[111111];
int vis[111111], r[111111], o[1111111];
int len[111111];
long long cost = 0;

void dfs(int u)
{
    vis[u] = 1;
    for(int i=0;i<adj[u].size();i++)
    {
        len[cc] += adj[u][i].second;
        int v = adj[u][i].first;
        if(!vis[v])
        {
            o[cc] = v;
            dfs(v);
        }
    }
}

int main()
{
    int n, m, p, q;
    cc = 0;
    cin >> n >> m >> p >> q;
    for(int i=0;i<m;i++)
    {
        int a, b, l;
        cin >> a >> b >> l;
        adj[a].push_back(make_pair(b,l));
        adj[b].push_back(make_pair(a,l));
    }
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            dfs(i);
            r[cc] = i;
            len[cc++] /= 2;
        }
    }
    priority_queue <pair<long long,int> >  pq;
    vector <pair<int,int> > v;
    for(int i=0;i<cc;i++) pq.push(make_pair(-len[i],i));
    while(q < pq.size())
    {
        if(p == 0) break;
        pair <long long,int> x, y, z;
        x = pq.top(); pq.pop();
        y = pq.top(); pq.pop();
        r[cc] = r[x.second];
        o[cc] = r[y.second];
        if(1 - x.first - y.first > 1000000000)
        {
            z.first = x.first + y.first - 1000000000;
            cost += 1000000000;
        }
        else
        {
            z.first = 2*(x.first+y.first)-1;
            cost -= (x.first+y.first-1);
        }
        z.second = cc++;
        pq.push(z);
        v.push_back(make_pair(r[x.second],r[y.second]));
        p--;
    }
    if(pq.size() != q) cout << "NO" << endl;
    else
    {
        if(p)
        {
            pair <int,int> x;
            while(!pq.empty() && o[pq.top().second] == 0) pq.pop();
            if(!pq.empty())
            {
                x = pq.top(); pq.pop();
                while(p)
                {
                    v.push_back(make_pair(r[x.second],o[x.second]));
                    p--;
                }
            }
        }
        if(p) cout << "NO" << endl;
        else
        {
            cout << "YES" << endl;
            for(int i=0;i<v.size();i++) cout << v[i].first << " " << v[i].second << endl;
        }
    }
    return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#define inf 1000000007

using namespace std;

int cc;
vector <pair<int,int> > adj[111111];
int vis[111111], r[111111], o[1111111];
int len[111111];

void dfs(int u)
{
    vis[u] = 1;
    o[cc] = u;
    for(int i=0;i<adj[u].size();i++)
    {
        len[cc] = min(1000000000,len[cc]+adj[u][i].second);
        int v = adj[u][i].first;
        if(!vis[v]) dfs(v);
    }
}

int main()
{
    int n, m, p, q;
    cc = 0;
    cin >> n >> m >> p >> q;
    for(int i=0;i<m;i++)
    {
        int a, b, l;
        cin >> a >> b >> l;
        adj[a].push_back(make_pair(b,l));
        adj[b].push_back(make_pair(a,l));
    }
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            dfs(i);
            r[cc] = i;
            len[cc++] /= 2;
        }
    }
    priority_queue <pair<int,int> >  pq;
    vector <pair<int,int> > v;
    for(int i=0;i<cc;i++) pq.push(make_pair(-len[i],i));
    while(q < pq.size())
    {
        if(p == 0) break;
        pair <int,int> x, y, z;
        x = pq.top(); pq.pop();
        y = pq.top(); pq.pop();
        r[cc] = r[x.second];
        o[cc] = r[y.second];
        z.first = max(-1000000000, x.first + y.first - 1);
        z.second = cc++;
        pq.push(z);
        v.push_back(make_pair(r[x.second],r[y.second]));
        p--;
    }
    if(pq.size() != q) cout << "NO" << endl;
    else
    {
        if(p)
        {
            pair <int,int> x;
            while(!pq.empty() && o[pq.top().second] == 0) pq.pop();
            if(!pq.empty())
            {
                x = pq.top(); pq.pop();
                while(p--) v.push_back(make_pair(r[x.second],o[x.second]));
            }
        }
        if(p) cout << "NO" << endl;
        else
        {
            cout << "YES" << endl;
            for(int i=0;i<v.size();i++) cout << v[i].first << " " << v[i].second << endl;
        }
    }
    return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#define inf 1000000007

using namespace std;

int cc;
vector <pair<int,int> > adj[111111];
int vis[111111], r[111111], o[1111111];
int len[111111];
long long cost = 0;

void dfs(int u)
{
    vis[u] = 1;
    for(int i=0;i<adj[u].size();i++)
    {
        len[cc] = min(1000000000,len[cc]+adj[u][i].second);
        int v = adj[u][i].first;
        if(!vis[v])
        {
            o[cc] = v;
            dfs(v);
        }
    }
}

int main()
{
    int n, m, p, q;
    cc = 0;
    cin >> n >> m >> p >> q;
    for(int i=0;i<m;i++)
    {
        int a, b, l;
        cin >> a >> b >> l;
        adj[a].push_back(make_pair(b,l));
        adj[b].push_back(make_pair(a,l));
    }
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            dfs(i);
            r[cc] = i;
            len[cc++] /= 2;
        }
    }
    priority_queue <pair<long long,int> >  pq;
    vector <pair<int,int> > v;
    for(int i=0;i<cc;i++) pq.push(make_pair(-len[i],i));
    while(q < pq.size())
    {
        if(p == 0) break;
        pair <long long,int> x, y, z;
        x = pq.top(); pq.pop();
        y = pq.top(); pq.pop();
        r[cc] = r[x.second];
        o[cc] = r[y.second];
        z.first = max(-1000000000ll, 2*(x.first+y.first)-1);
        z.second = cc++;
        pq.push(z);
        v.push_back(make_pair(r[x.second],r[y.second]));
        p--;
    }
    if(pq.size() != q) cout << "NO" << endl;
    else
    {
        if(p)
        {
            pair <int,int> x;
            while(!pq.empty() && o[pq.top().second] == 0) pq.pop();
            if(!pq.empty())
            {
                x = pq.top(); pq.pop();
                while(p)
                {
                    v.push_back(make_pair(r[x.second],o[x.second]));
                    p--;
                }
            }
        }
        if(p) cout << "NO" << endl;
        else
        {
            cout << "YES" << endl;
            for(int i=0;i<v.size();i++) cout << v[i].first << " " << v[i].second << endl;
        }
    }
    return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#define inf 1000000007

using namespace std;

int cc;
vector <pair<int,int> > adj[111111];
int vis[111111], r[111111], o[1111111];
int len[111111];
long long cost = 0;

void dfs(int u)
{
    vis[u] = 1;
    for(int i=0;i<adj[u].size();i++)
    {
        len[cc] = min(1000000000,len[cc]+adj[u][i].second);
        int v = adj[u][i].first;
        if(!vis[v])
        {
            o[cc] = v;
            dfs(v);
        }
    }
}

int main()
{
    int n, m, p, q;
    cc = 0;
    cin >> n >> m >> p >> q;
    for(int i=0;i<m;i++)
    {
        int a, b, l;
        cin >> a >> b >> l;
        adj[a].push_back(make_pair(b,l));
        adj[b].push_back(make_pair(a,l));
    }
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            dfs(i);
            r[cc] = i;
            len[cc++] /= 2;
        }
    }
    priority_queue <pair<long long,int> >  pq;
    vector <pair<int,int> > v;
    for(int i=0;i<cc;i++) pq.push(make_pair(-len[i],i));
    while(q < pq.size())
    {
        if(p == 0) break;
        pair <long long,int> x, y, z;
        x = pq.top(); pq.pop();
        y = pq.top(); pq.pop();
        r[cc] = r[x.second];
        o[cc] = r[y.second];
        z.first = x.first + y.first;
        z.second = cc++;
        pq.push(z);
        v.push_back(make_pair(r[x.second],r[y.second]));
        p--;
    }
    if(pq.size() != q) cout << "NO" << endl;
    else
    {
        if(p)
        {
            pair <int,int> x;
            while(!pq.empty() && o[pq.top().second] == 0) pq.pop();
            if(!pq.empty())
            {
                x = pq.top(); pq.pop();
                while(p)
                {
                    v.push_back(make_pair(r[x.second],o[x.second]));
                    p--;
                }
            }
        }
        if(p) cout << "NO" << endl;
        else
        {
            cout << "YES" << endl;
            for(int i=0;i<v.size();i++) cout << v[i].first << " " << v[i].second << endl;
        }
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair <int,int> pii;
typedef vector <int> vi;

#define rep(i, n) for(int i = 0; i < (n); ++i)
#define forn(i, a, b) for(int i = (a); i < (b); ++i)
#define ford(i, a, b) for(int i = (a); i >= (b); --i)
#define fore(i, a, b) forn(i, a, b + 1)

#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define all(c) c.begin(), c.end()
#define mset(a, v) memset(a, v, sizeof(a))
#define sz(a) ((int)a.size())

#define gi(x) scanf("%d", &x)
#define pis(x) printf("%d ", x)
#define pin(x) printf("%d\n", x)
#define pnl printf("\n")
#define dbn cerr << "\n"
#define dbg(x) cerr << #x << " : " << (x) << " "
#define dbs(x) cerr << (x) << " "

#define foreach(c, it) for(__typeof(c.begin()) it = c.begin(); it != c.end(); ++it)

const int N = 100100;
const int LIM = (int)1e9;

int root[N], sum[N], size[N];

int get(int n) {
    if(root[n] != n)
        root[n] = get(root[n]);
    return root[n];
}

inline void add(int &a, int b) {
    a += b;
    if(a >= LIM) a = LIM;
}

inline void merge(int x, int y) {
    x = get(x), y = get(y);
    if(x != y) {
        root[y] = x;
        add(sum[x], sum[y]);
        sum[y] = 0;
    }
}

vi adj[N];

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

    rep(i, n) root[i] = i, sum[i] = 0;

    rep(i, m) {
        int u, v, w;
        gi(u), gi(v), gi(w);
        --u; --v;
        merge(u, v);
        add(sum[get(u)], w);
    }

    int numComps = 0;

    priority_queue <pii, vector <pii>, greater <pii> > Q;

    rep(i, n) if(get(i) == i) {
        ++numComps;
        Q.push(mp(sum[i], i));
    }

    if(numComps < q or numComps - p > q) puts("NO");
    else {
        int extra = p - (numComps - q);
        vector <pii> ans;
        p = (numComps - q);
        while(p--) {
            pii first = Q.top(); Q.pop();
            pii second = Q.top(); Q.pop();

            int u = first.ss, v = second.ss;

            ans.pb(mp(u + 1, v + 1));

            merge(u, v);
            add(sum[get(u)], +1);

            Q.push(mp(sum[get(u)], u));
        }
        int child = -1;
        rep(i, n) if(get(i) != i) child = i;
        if(extra > 0 and child == -1) puts("NO");
        else {
            puts("YES");
            foreach(ans, it) pis(it->ff), pin(it->ss);
            while(extra--) pis(get(child) + 1), pin(child + 1);
        }
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair <int,int> pii;
typedef vector <int> vi;

#define rep(i, n) for(int i = 0; i < (n); ++i)
#define forn(i, a, b) for(int i = (a); i < (b); ++i)
#define ford(i, a, b) for(int i = (a); i >= (b); --i)
#define fore(i, a, b) forn(i, a, b + 1)

#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define all(c) c.begin(), c.end()
#define mset(a, v) memset(a, v, sizeof(a))
#define sz(a) ((int)a.size())

#define gi(x) scanf("%d", &x)
#define pis(x) printf("%d ", x)
#define pin(x) printf("%d\n", x)
#define pnl printf("\n")
#define dbn cerr << "\n"
#define dbg(x) cerr << #x << " : " << (x) << " "
#define dbs(x) cerr << (x) << " "

#define foreach(c, it) for(__typeof(c.begin()) it = c.begin(); it != c.end(); ++it)

const int N = 100100;
const int LIM = (int)1e9;

int root[N], sum[N], size[N];

int get(int n) {
    if(root[n] != n)
        root[n] = get(root[n]);
    return root[n];
}

inline void add(int &a, int b) {
    a += b;
    if(a >= LIM) a = LIM;
}

inline void merge(int x, int y) {
    x = get(x), y = get(y);
    if(x != y) {
        root[y] = x;
        add(sum[x], sum[y]);
        sum[y] = 0;
    }
}

vi adj[N];

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

    rep(i, n) root[i] = i, sum[i] = 0;

    rep(i, m) {
        int u, v, w;
        gi(u), gi(v), gi(w);
        --u; --v;
        merge(u, v);
        add(sum[get(u)], w);
    }

    int numComps = 0;

    priority_queue <pii, vector <pii>, greater <pii> > Q;

    rep(i, n) if(root[i] == i) {
        ++numComps;
        Q.push(mp(sum[i], i));
    }

    if(numComps < q or numComps - p > q) puts("NO");
    else {
        int extra = p - (numComps - q);

        if(extra > 0 and numComps == n) {
            puts("NO");
            return 0;
        }
        puts("YES");
        p = (numComps - q);
        while(p--) {
            pii first = Q.top(); Q.pop();
            pii second = Q.top(); Q.pop();

            int u = first.ss, v = second.ss;

            pis(u + 1), pin(v + 1);

            merge(u, v);
            add(sum[get(u)], +1);

            Q.push(mp(sum[get(u)], u));
        }

        mset(size, 0);
        rep(i, n) size[get(i)]++;
        int p = -1, q = -1;
        rep(i, n) if(size[get(i)] > 1) p = i;
        rep(i, n) if(size[get(i)] > 1 and i != p) q = i;

        while(extra--) pis(p + 1), pin(q + 1);
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair <int,int> pii;
typedef vector <int> vi;

#define rep(i, n) for(int i = 0; i < (n); ++i)
#define forn(i, a, b) for(int i = (a); i < (b); ++i)
#define ford(i, a, b) for(int i = (a); i >= (b); --i)
#define fore(i, a, b) forn(i, a, b + 1)

#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define all(c) c.begin(), c.end()
#define mset(a, v) memset(a, v, sizeof(a))
#define sz(a) ((int)a.size())

#define gi(x) scanf("%d", &x)
#define pis(x) printf("%d ", x)
#define pin(x) printf("%d\n", x)
#define pnl printf("\n")
#define dbn cerr << "\n"
#define dbg(x) cerr << #x << " : " << (x) << " "
#define dbs(x) cerr << (x) << " "

#define foreach(c, it) for(__typeof(c.begin()) it = c.begin(); it != c.end(); ++it)

const int N = 100100;
const int LIM = (int)1e9;

int root[N], sum[N], size[N];

int get(int n) {
    if(root[n] != n)
        root[n] = get(root[n]);
    return root[n];
}

inline void add(int &a, int b) {
    a += b;
    if(a >= LIM) a = LIM;
}

inline void merge(int x, int y) {
    x = get(x), y = get(y);
    if(x != y) {
        root[y] = x;
        add(sum[x], sum[y]);
        sum[y] = 0;
    }
}

vi adj[N];

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

    rep(i, n) root[i] = i, sum[i] = 0;

    rep(i, m) {
        int u, v, w;
        gi(u), gi(v), gi(w);
        --u; --v;
        merge(u, v);
        add(sum[get(u)], w);
    }

    int numComps = 0;

    priority_queue <pii, vector <pii>, greater <pii> > Q;

    rep(i, n) if(get(i) == i) {
        ++numComps;
        Q.push(mp(sum[i], i));
    }

    if(numComps < q or numComps - p > q) puts("NO");
    else {
        int extra = p - (numComps - q);
        vector <pii> ans;
        p = (numComps - q);

        while(p--) {
            pii first = Q.top(); Q.pop();
            pii second = Q.top(); Q.pop();

            int u = first.ss, v = second.ss;

            ans.pb(mp(u + 1, v + 1));

            merge(u, v);
            u = get(u);

            int curWt = sum[u];
            add(curWt, 1);
            add(sum[u], curWt);

            Q.push(mp(sum[u], u));
        }
        int child = -1;
        rep(i, n) if(get(i) != i) child = i;
        if(extra > 0 and child == -1) puts("NO");
        else {
            puts("YES");
            foreach(ans, it) pis(it->ff), pin(it->ss);
            while(extra--) pis(get(child) + 1), pin(child + 1);
        }
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair <int,int> pii;
typedef vector <int> vi;

#define rep(i, n) for(int i = 0; i < (n); ++i)
#define forn(i, a, b) for(int i = (a); i < (b); ++i)
#define ford(i, a, b) for(int i = (a); i >= (b); --i)
#define fore(i, a, b) forn(i, a, b + 1)

#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define all(c) c.begin(), c.end()
#define mset(a, v) memset(a, v, sizeof(a))
#define sz(a) ((int)a.size())

#define gi(x) scanf("%d", &x)
#define pis(x) printf("%d ", x)
#define pin(x) printf("%d\n", x)
#define pnl printf("\n")
#define dbn cerr << "\n"
#define dbg(x) cerr << #x << " : " << (x) << " "
#define dbs(x) cerr << (x) << " "

#define foreach(c, it) for(__typeof(c.begin()) it = c.begin(); it != c.end(); ++it)

const int N = 100100;
const int LIM = (int)1e9;

int root[N], sum[N];

int get(int n) {
    if(root[n] != n)
        root[n] = get(root[n]);
    return root[n];
}

inline void add(int &a, int b) {
    a += b;
    if(a >= LIM) a = LIM;
}

inline void merge(int x, int y) {
    x = get(x), y = get(y);
    if(x != y) {
        root[y] = x;
        add(sum[x], sum[y]);
        sum[y] = 0;
    }
}

vi adj[N];

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

    rep(i, n) root[i] = i, sum[i] = 0;

    rep(i, m) {
        int u, v, w;
        gi(u), gi(v), gi(w);
        --u; --v;
        merge(u, v);
        add(sum[get(u)], w);
    }

    int numComps = 0;

    priority_queue <pii, vector <pii>, greater <pii> > Q;

    rep(i, n) if(root[i] == i) {
        ++numComps;
        Q.push(mp(sum[i], i));
    }

    if(numComps < q or numComps - p > q) puts("NO");
    else {
        int extra = p - (numComps - q);

        if(extra > 0 and numComps == n) {
            puts("NO");
            return 0;
        }
        puts("YES");
        p = (numComps - q);
        while(p--) {
            pii first = Q.top(); Q.pop();
            pii second = Q.top(); Q.pop();

            int u = first.ss, v = second.ss;

            pis(u + 1), pin(v + 1);

            merge(u, v);
            add(sum[get(u)], +1);

            Q.push(mp(sum[get(u)], u));
        }
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair <int,int> pii;
typedef vector <int> vi;

#define rep(i, n) for(int i = 0; i < (n); ++i)
#define forn(i, a, b) for(int i = (a); i < (b); ++i)
#define ford(i, a, b) for(int i = (a); i >= (b); --i)
#define fore(i, a, b) forn(i, a, b + 1)

#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define all(c) c.begin(), c.end()
#define mset(a, v) memset(a, v, sizeof(a))
#define sz(a) ((int)a.size())

#define gi(x) scanf("%d", &x)
#define pis(x) printf("%d ", x)
#define pin(x) printf("%d\n", x)
#define pnl printf("\n")
#define dbn cerr << "\n"
#define dbg(x) cerr << #x << " : " << (x) << " "
#define dbs(x) cerr << (x) << " "

#define foreach(c, it) for(__typeof(c.begin()) it = c.begin(); it != c.end(); ++it)

const int N = 100100;
const int LIM = (int)1e9;

int root[N], sum[N], size[N];

int get(int n) {
    if(root[n] != n)
        root[n] = get(root[n]);
    return root[n];
}

inline void add(int &a, int b) {
    a += b;
    if(a >= LIM) a = LIM;
}

inline void merge(int x, int y) {
    x = get(x), y = get(y);
    if(x != y) {
        root[y] = x;
        add(sum[x], sum[y]);
        sum[y] = 0;
    }
}

vi adj[N];

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

    rep(i, n) root[i] = i, sum[i] = 0;

    rep(i, m) {
        int u, v, w;
        gi(u), gi(v), gi(w);
        --u; --v;
        merge(u, v);
        add(sum[get(u)], w);
    }

    int numComps = 0;

    priority_queue <pii, vector <pii>, greater <pii> > Q;

    rep(i, n) if(get(i) == i) {
        ++numComps;
        Q.push(mp(sum[i], i));
    }

    if(numComps < q or numComps - p > q) puts("NO");
    else {
        int extra = p - (numComps - q);

        vector <pii> ans;
        puts("YES");
        p = (numComps - q);
        while(p--) {
            pii first = Q.top(); Q.pop();
            pii second = Q.top(); Q.pop();

            int u = first.ss, v = second.ss;

            ans.pb(mp(u + 1, v + 1));

            merge(u, v);
            add(sum[get(u)], +1);

            Q.push(mp(sum[get(u)], u));
        }
        if(extra > 0) {
            int child = -1;
            rep(i, n) if(get(i) != i) child = i;
            if(child == -1) puts("NO");
            else {
                foreach(ans, it) pis(it->ff), pin(it->ss);
                while(extra--) pis(child + 1), pin(get(child) + 1);
            }
        }
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair <int,int> pii;
typedef vector <int> vi;

#define rep(i, n) for(int i = 0; i < (n); ++i)
#define forn(i, a, b) for(int i = (a); i < (b); ++i)
#define ford(i, a, b) for(int i = (a); i >= (b); --i)
#define fore(i, a, b) forn(i, a, b + 1)

#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define all(c) c.begin(), c.end()
#define mset(a, v) memset(a, v, sizeof(a))
#define sz(a) ((int)a.size())

#define gi(x) scanf("%d", &x)
#define pis(x) printf("%d ", x)
#define pin(x) printf("%d\n", x)
#define pnl printf("\n")
#define dbn cerr << "\n"
#define dbg(x) cerr << #x << " : " << (x) << " "
#define dbs(x) cerr << (x) << " "

#define foreach(c, it) for(__typeof(c.begin()) it = c.begin(); it != c.end(); ++it)

const int N = 100100;
const int LIM = (int)1e9;

int root[N], sum[N], size[N];

int get(int n) {
    if(root[n] != n)
        root[n] = get(root[n]);
    return root[n];
}

inline void add(int &a, int b) {
    a += b;
    if(a >= LIM) a = LIM;
}

inline void merge(int x, int y) {
    x = get(x), y = get(y);
    if(x != y) {
        root[y] = x;
        add(sum[x], sum[y]);
        sum[y] = 0;
    }
}

vi adj[N];

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

    rep(i, n) root[i] = i, sum[i] = 0;

    rep(i, m) {
        int u, v, w;
        gi(u), gi(v), gi(w);
        --u; --v;
        merge(u, v);
        add(sum[get(u)], w);
    }

    int numComps = 0, child = -1;

    priority_queue <pii, vector <pii>, greater <pii> > Q;

    rep(i, n) if(root[i] == i) {
        ++numComps;
        Q.push(mp(sum[i], i));
    } else child = i;

    if(numComps < q or numComps - p > q) puts("NO");
    else {
        int extra = p - (numComps - q);

        if(extra > 0 and numComps == n) {
            puts("NO");
            return 0;
        }
        puts("YES");
        p = (numComps - q);
        while(p--) {
            pii first = Q.top(); Q.pop();
            pii second = Q.top(); Q.pop();

            int u = first.ss, v = second.ss;

            pis(u + 1), pin(v + 1);

            merge(u, v);
            add(sum[get(u)], +1);

            Q.push(mp(sum[get(u)], u));
        }
        while(extra--) pis(child + 1), pin(get(child) + 1);
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair <int,int> pii;
typedef vector <int> vi;

#define rep(i, n) for(int i = 0; i < (n); ++i)
#define forn(i, a, b) for(int i = (a); i < (b); ++i)
#define ford(i, a, b) for(int i = (a); i >= (b); --i)
#define fore(i, a, b) forn(i, a, b + 1)

#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define all(c) c.begin(), c.end()
#define mset(a, v) memset(a, v, sizeof(a))
#define sz(a) ((int)a.size())

#define gi(x) scanf("%d", &x)
#define pis(x) printf("%d ", x)
#define pin(x) printf("%d\n", x)
#define pnl printf("\n")
#define dbn cerr << "\n"
#define dbg(x) cerr << #x << " : " << (x) << " "
#define dbs(x) cerr << (x) << " "

#define foreach(c, it) for(__typeof(c.begin()) it = c.begin(); it != c.end(); ++it)

const int N = 100100;
const int LIM = (int)1e9;

int root[N], sum[N], size[N];

int get(int n) {
    if(root[n] != n)
        root[n] = get(root[n]);
    return root[n];
}

inline void add(int &a, int b) {
    a += b;
    if(a >= LIM) a = LIM;
}

inline void merge(int x, int y) {
    x = get(x), y = get(y);
    if(x != y) {
        root[y] = x;
        add(sum[x], sum[y]);
        sum[y] = 0;
    }
}

vi adj[N];

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

    rep(i, n) root[i] = i, sum[i] = 0;

    rep(i, m) {
        int u, v, w;
        gi(u), gi(v), gi(w);
        --u; --v;
        merge(u, v);
        add(sum[get(u)], w);
    }

    int numComps = 0;

    priority_queue <pii, vector <pii>, greater <pii> > Q;

    rep(i, n) if(root[i] == i) {
        ++numComps;
        Q.push(mp(sum[i], i));
    }

    if(numComps < q or numComps - p > q) puts("NO");
    else {
        int extra = p - (numComps - q);

        if(extra > 0 and numComps == n) {
            puts("NO");
            return 0;
        }
        puts("YES");
        p = (numComps - q);
        while(p--) {
            pii first = Q.top(); Q.pop();
            pii second = Q.top(); Q.pop();

            int u = first.ss, v = second.ss;

            pis(u + 1), pin(v + 1);

            merge(u, v);
            add(sum[get(u)], +1);

            Q.push(mp(sum[get(u)], u));
        }

        mset(size, 0);
        rep(i, n) size[get(i)]++;
        int p = -1, q = -1;
        rep(i, n) if(size[get(i)] > 1) p = i;
        rep(i, n) if(size[get(i)] > 1 and i != p) q = i;

        while(extra--) pis(p), pin(q);
    }
    return 0;
}


//In the name of God
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>

#define X first
#define Y second
// #define X real()
// #define Y imag()
// #define cin fin
// #define cout fout

using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
const int maxn = 1e5;

ll n, m, p, q, par[maxn], sum[maxn];
vector<pair<ll, pll> > e;
vector<pll> ans;
set<pll> s;

inline ll findpar (ll u)
{
  return (par[u] == u ? u : par[u] = findpar(par[u]));
}

int main ()
{
  ios_base :: sync_with_stdio(0);
  cin >> n >> m >> p >> q ;
  if(m + p > 0 && q == n)
    {
      cout << "NO" << endl ;
      exit(0);
    }
  for(ll u, v, w, i = 0 ; i < m ; i++)
    {
      cin >> u >> v >> w ;
      u --, v --;
      e.push_back(make_pair(w, pll(u, v)));
    }
  sort(e.begin(), e.end());
  for(ll i = 0 ; i < n ; i++)
    par[i] = i;
  for(ll i = 0 ; i < e.size() ; i++)
    {
      ll v = e[i].Y.X, u = e[i].Y.Y, w = e[i].X, vpar = findpar(v), upar = findpar(u);
      sum[vpar] += w;
      if(upar != vpar)
	{
	  par[upar] = vpar;
	  sum[vpar] += sum[upar];
	  sum[upar] = 0;
	}
    }
  for(ll i = 0 ; i < n ; i++)
    {
      ll p = findpar(i);
      s.insert(pll(sum[p], p));
    }
  if(s.size() < q)
    {
      cout << "NO" << endl ;
      exit(0);
    }
  for(ll i = 0 ; i < p ; i++)
    {
      if(s.size() == q)
	break;
      while(s.size() < 2);
      ll u = s.begin()->Y;
      s.erase(*s.begin());
      ll v = s.begin()->Y;
      s.erase(*s.begin());
      ll w = min((ll)1e9, sum[u] + sum[v] + 1);
      par[u] = v;
      sum[v] += sum[u] + w;
      sum[u] = 0;
      s.insert(pll(sum[v], v));
      ans.push_back(pll(v, u));
    }
  while(ans.size() < p)
    ans.push_back(ans.size() ? ans[0] : e[0].Y);
  if(s.size() > q)
    cout << "NO" << endl ;
  else
    {
      cout << "YES" << endl ;
      for(ll i = 0 ; i < ans.size() ; i++)
	cout << ans[i].X + 1 << ' ' << ans[i].Y + 1 << endl ;
    }
}


//In the name of God
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>

#define X first
#define Y second
// #define X real()
// #define Y imag()
// #define cin fin
// #define cout fout

using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
const int maxn = 1e5;

ll n, m, p, q, par[maxn], sum[maxn];
vector<pair<ll, pll> > e;
vector<pll> ans;
set<pll> s;

inline ll findpar (ll u)
{
  return (par[u] == u ? u : par[u] = findpar(par[u]));
}

int main ()
{
  ios_base :: sync_with_stdio(0);
  cin >> n >> m >> p >> q ;
  if(m + p > 0 && q == n)
    {
      cout << "NO" << endl ;
      exit(0);
    }
  for(ll u, v, w, i = 0 ; i < m ; i++)
    {
      cin >> u >> v >> w ;
      u --, v --;
      e.push_back(make_pair(w, pll(u, v)));
    }
  sort(e.begin(), e.end());
  for(ll i = 0 ; i < n ; i++)
    par[i] = i;
  for(ll i = 0 ; i < e.size() ; i++)
    {
      ll v = e[i].Y.X, u = e[i].Y.Y, w = e[i].X, vpar = findpar(v), upar = findpar(u);
      sum[vpar] += w;
      if(upar != vpar)
	{
	  par[upar] = vpar;
	  sum[vpar] += sum[upar];
	  sum[upar] = 0;
	}
    }
  for(ll i = 0 ; i < n ; i++)
    {
      ll p = findpar(i);
      s.insert(pll(sum[p], p));
    }
  if(s.size() < q)
    {
      cout << "NO" << endl ;
      exit(0);
    }
  for(ll i = 0 ; i < p ; i++)
    {
      if(s.size() == q)
	break;
      while(s.size() < 2);
      ll u = s.begin()->Y;
      s.erase(*s.begin());
      ll v = s.begin()->Y;
      s.erase(*s.begin());
      ll w = min((ll)1e9, sum[u] + sum[v] + 1);
      par[u] = v;
      sum[v] += sum[u] + w;
      sum[u] = 0;
      s.insert(pll(sum[v], v));
      ans.push_back(pll(v, u));
    }
  while(ans.size() < p)
    ans.push_back(e[0].Y);
  if(s.size() > q)
    cout << "NO" << endl ;
  else
    {
      cout << "YES" << endl ;
      for(ll i = 0 ; i < ans.size() ; i++)
	cout << ans[i].X + 1 << ' ' << ans[i].Y + 1 << endl ;
    }
}


//In the name of God
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>

#define X first
#define Y second
// #define X real()
// #define Y imag()
// #define cin fin
// #define cout fout

using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
const int maxn = 1e5;

ll n, m, p, q, par[maxn], sum[maxn];
vector<pair<ll, pll> > e;
vector<pll> ans;
set<pll> s;

inline ll findpar (ll u)
{
  return (par[u] == u ? u : par[u] = findpar(par[u]));
}

int main ()
{
  ios_base :: sync_with_stdio(0);
  cin >> n >> m >> p >> q ;
  if(m + p > 0 && q == n)
    {
      cout << "NO" << endl ;
      exit(0);
    }
  for(ll u, v, w, i = 0 ; i < m ; i++)
    {
      cin >> u >> v >> w ;
      u --, v --;
      e.push_back(make_pair(w, pll(u, v)));
    }
  sort(e.begin(), e.end());
  for(ll i = 0 ; i < n ; i++)
    par[i] = i;
  for(ll i = 0 ; i < e.size() ; i++)
    {
      ll v = e[i].Y.X, u = e[i].Y.Y, w = e[i].X, vpar = findpar(v), upar = findpar(u);
      sum[vpar] += w;
      if(upar != vpar)
	{
	  par[upar] = vpar;
	  sum[vpar] += sum[upar];
	  sum[upar] = 0;
	}
    }
  for(ll i = 0 ; i < n ; i++)
    {
      ll p = findpar(i);
      s.insert(pll(sum[p], p));
    }
  if(s.size() < q)
    {
      cout << "NO" << endl ;
      exit(0);
    }
  for(ll i = 0 ; i < p ; i++)
    {
      if(s.size() == q)
	break;
      ll u = s.begin()->Y;
      s.erase(*s.begin());
      ll v = s.begin()->Y;
      s.erase(*s.begin());
      ll w = min((ll)1e9, sum[u] + sum[v]);
      par[u] = v;
      sum[v] += sum[u] + w;
      sum[u] = 0;
      s.insert(pll(sum[v], v));
      ans.push_back(pll(v, u));
    }
  while(ans.size() < p)
    ans.push_back(e[0].Y);
  if(s.size() > q)
    cout << "NO" << endl ;
  else
    {
      cout << "YES" << endl ;
      for(ll i = 0 ; i < ans.size() ; i++)
	cout << ans[i].X + 1 << ' ' << ans[i].Y + 1 << endl ;
    }
}


//In the name of God
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>

#define X first
#define Y second
// #define X real()
// #define Y imag()
// #define cin fin
// #define cout fout

using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
const int maxn = 2 * 1e5;

ll n, m, p, q, par[maxn], sum[maxn];
vector<pair<ll, pll> > e;
vector<pll> ans;
set<pll> s;

inline ll findpar (ll u)
{
  return (par[u] == u ? u : par[u] = findpar(par[u]));
}

int main ()
{
  ios_base :: sync_with_stdio(0);
  cin >> n >> m >> p >> q ;
  if(m + p > 0 && q == n)
    {
      cout << "NO" << endl ;
      exit(0);
    }
  for(ll u, v, w, i = 0 ; i < m ; i++)
    {
      cin >> u >> v >> w ;
      u --, v --;
      e.push_back(make_pair(w, pll(u, v)));
    }
  sort(e.begin(), e.end());
  for(ll i = 0 ; i < n ; i++)
    par[i] = i;
  for(ll i = 0 ; i < e.size() ; i++)
    {
      ll v = e[i].Y.X, u = e[i].Y.Y, w = e[i].X, vpar = findpar(v), upar = findpar(u);
      sum[vpar] += w;
      if(upar != vpar)
	{
	  par[upar] = vpar;
	  sum[vpar] += sum[upar];
	  sum[upar] = 0;
	}
    }
  for(ll i = 0 ; i < n ; i++)
    {
      ll p = findpar(i);
      s.insert(pll(sum[p], p));
    }
  if(s.size() < q)
    {
      cout << "NO" << endl ;
      exit(0);
    }
  for(ll i = 0 ; i < p ; i++)
    {
      if(s.size() == q)
	break;
      while(s.size() < 2);
      ll u = s.begin()->Y;
      s.erase(*s.begin());
      ll v = s.begin()->Y;
      s.erase(*s.begin());
      ll w = min((ll)1e9, sum[u] + sum[v] + 1);
      par[u] = v;
      sum[v] += sum[u] + w;
      sum[u] = 0;
      s.insert(pll(sum[v], v));
      ans.push_back(pll(v, u));
    }
  while(ans.size() < p)
    ans.push_back(e[0].Y);
  if(s.size() > q)
    cout << "NO" << endl ;
  else
    {
      cout << "YES" << endl ;
      for(ll i = 0 ; i < ans.size() ; i++)
	cout << ans[i].X + 1 << ' ' << ans[i].Y + 1 << endl ;
    }
}


//In the name of God
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>

#define X first
#define Y second
// #define X real()
// #define Y imag()
// #define cin fin
// #define cout fout

using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
const int maxn = 1e5;

ll n, m, p, q, par[maxn], sum[maxn];
vector<pair<ll, pll> > e;
vector<pll> ans;
set<pll> s;

inline int findpar (int u)
{
  return (par[u] == u ? u : par[u] = findpar(par[u]));
}

int main ()
{
  ios_base :: sync_with_stdio(0);
  cin >> n >> m >> p >> q ;
  if(m + p > 0 && q == n)
    {
      cout << "NO" << endl ;
      exit(0);
    }
  for(int u, v, w, i = 0 ; i < m ; i++)
    {
      cin >> u >> v >> w ;
      u --, v --;
      e.push_back(make_pair(w, pll(u, v)));
    }
  sort(e.begin(), e.end());
  for(int i = 0 ; i < n ; i++)
    par[i] = i;
  for(int i = 0 ; i < e.size() ; i++)
    {
      int v = e[i].Y.X, u = e[i].Y.Y, w = e[i].X, vpar = findpar(v), upar = findpar(u);
      sum[vpar] += w;
      if(upar != vpar)
	{
	  par[upar] = vpar;
	  sum[vpar] += sum[upar];
	  sum[upar] = 0;
	}
    }
  for(int i = 0 ; i < n ; i++)
    {
      int p = findpar(i);
      s.insert(pll(sum[p], p));
    }
  if(s.size() < q)
    {
      cout << "NO" << endl ;
      exit(0);
    }
  for(int i = 0 ; i < p ; i++)
    {
      if(s.size() == q)
	break;
      int u = s.begin()->Y;
      s.erase(*s.begin());
      int v = s.begin()->Y;
      s.erase(*s.begin());
      int w = min((ll)1e9, sum[u] + sum[v]);
      par[u] = v;
      sum[v] += sum[u] + w;
      sum[u] = 0;
      s.insert(pll(sum[v], v));
      ans.push_back(pll(v, u));
    }
  while(ans.size() < p)
    ans.push_back(e[0].Y);
  if(s.size() > q)
    cout << "NO" << endl ;
  else
    {
      cout << "YES" << endl ;
      for(int i = 0 ; i < ans.size() ; i++)
	cout << ans[i].X + 1 << ' ' << ans[i].Y + 1 << endl ;
    }
}


//In the name of God
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>

#define X first
#define Y second
// #define X real()
// #define Y imag()
// #define cin fin
// #define cout fout

using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
const int maxn = 1e5;

ll n, m, p, q, par[maxn], sum[maxn];
vector<pair<ll, pll> > e;
vector<pll> ans;
set<pll> s;

inline ll findpar (ll u)
{
  return (par[u] == u ? u : par[u] = findpar(par[u]));
}

int main ()
{
  ios_base :: sync_with_stdio(0);
  cin >> n >> m >> p >> q ;
  if(m + p > 0 && q == n)
    {
      cout << "NO" << endl ;
      exit(0);
    }
  for(ll u, v, w, i = 0 ; i < m ; i++)
    {
      cin >> u >> v >> w ;
      u --, v --;
      e.push_back(make_pair(w, pll(u, v)));
    }
  sort(e.begin(), e.end());
  for(ll i = 0 ; i < n ; i++)
    par[i] = i;
  for(ll i = 0 ; i < e.size() ; i++)
    {
      ll v = e[i].Y.X, u = e[i].Y.Y, w = e[i].X, vpar = findpar(v), upar = findpar(u);
      sum[vpar] += w;
      if(upar != vpar)
	{
	  par[upar] = vpar;
	  sum[vpar] += sum[upar];
	  sum[upar] = 0;
	}
    }
  for(ll i = 0 ; i < n ; i++)
    {
      ll p = findpar(i);
      s.insert(pll(sum[p], p));
    }
  if(s.size() < q)
    {
      cout << "NO" << endl ;
      exit(0);
    }
  for(ll i = 0 ; i < p ; i++)
    {
      if(s.size() == q)
	break;
      ll u = s.begin()->Y;
      s.erase(*s.begin());
      ll v = s.begin()->Y;
      s.erase(*s.begin());
      ll w = min((ll)1e9, sum[u] + sum[v] + 1);
      par[u] = v;
      sum[v] += sum[u] + w;
      sum[u] = 0;
      s.insert(pll(sum[v], v));
      ans.push_back(pll(v, u));
    }
  while(ans.size() < p)
    ans.push_back(e[0].Y);
  if(s.size() > q)
    cout << "NO" << endl ;
  else
    {
      cout << "YES" << endl ;
      for(ll i = 0 ; i < ans.size() ; i++)
	cout << ans[i].X + 1 << ' ' << ans[i].Y + 1 << endl ;
    }
}


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<ctime>
#include<assert.h>

#include<cmath>
#include<iostream>
#include<fstream>

#include<string>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<sstream>
#include<stack>
#include<limits.h>

using namespace std;

#define MAX(a,b) ((a)>(b) ? (a) : (b))
#define MIN(a,b) ((a)<(b) ? (a) : (b))
#define EPS 1e-9
#define asdf exit(0);

typedef __int64 LL;

#define Max 100010
int cs;
int parent[Max],rank[Max];
struct edge
{
    int source,dest;
    LL cost;
} e[Max];

vector<int> adj[Max];
LL dp[Max];

void link(int a,int b,LL w)   // just to decrease the time limit
{
    LL mn=w;
    //min(1000000000,dp[a]+dp[b]+1);
    if(rank[a]>rank[b])
    {
        parent[b]=a;
        dp[a]+=(dp[b]+mn);
        rank[a]+=rank[b];
    }
    else
    {
        dp[b]+=(dp[a]+mn);
        parent[a]=b;
        rank[b]+=rank[a];
    }
    return;
}

void link2(int a,int b)   // just to decrease the time limit
{
    LL mn=min( (LL)1000000000,dp[a]+dp[b]+1);

    if(rank[a]>rank[b])
    {
        parent[b]=a;
        dp[a]+=(dp[b]+mn);
        rank[a]+=rank[b];
    }
    else
    {
        dp[b]+=(dp[a]+mn);
        parent[a]=b;
        rank[b]+=rank[a];
    }
    return;
}

////finding the root of set
int find_set(int a)
{
    if(a!=parent[a])
        parent[a]=find_set(parent[a]);
    return parent[a];
}
//sorting edges in increasing order
bool operator<(edge a,edge b)
{
    return a.cost<b.cost;
}

void dfs(int u)
{
    int i,v;
    for(i=0;i<adj[u].size();i++)
    {
        v=adj[u][i];
        dp[v]+=dp[u];
        dfs(v);
    }
}

set<int> s;
struct cmp
{
    bool operator()(pair<int,int> a,pair<int,int> b)
    {
        return a.first>b.first;
    }
};
priority_queue< pair<int,int> , vector< pair<int,int> >, cmp > PQ;

vector< pair<int,int> > ans;

int main()
{
    int t,i,j,k,n,u,v,m,p,q;

    int X1,Y1;
    int got=0;

    //freopen("in.txt","r",stdin);
    //freopen("road.in","r",stdin);

    scanf("%d %d %d %d",&n,&m,&p,&q);

    for(i=0; i<n; i++)
    {
        parent[i]=i;
        rank[i]=1;
    }

    for(i=0; i<m; i++)
    {
        scanf("%d %d %I64d",&e[i].source,&e[i].dest,&e[i].cost);
        e[i].source--;
        e[i].dest--;

        got=1;
        X1=e[i].source;
        Y1=e[i].dest;

        u=find_set(e[i].source);
        v=find_set(e[i].dest);
        if(u!=v)
        {
            link(u,v,e[i].cost);
        }
        else
        {
            dp[u]+=1000;
        }
    }

    for(i=0;i<n;i++) s.insert(find_set(i));

    for(set<int>::iterator it=s.begin();it!=s.end();it++)
    {
        PQ.push(make_pair(dp[*it],*it));
    }

    int ok=1;

    pair<int,int> f1,f2;
    for(i=0;i<p;i++)
    {
        if(PQ.size()>q)
        {
            f1=PQ.top();PQ.pop();
            f2=PQ.top();PQ.pop();

            link2(f1.second,f2.second);

            got=1;
            X1=f1.second;
            Y1=f2.second;
        }
        else
        {
            if(!got)
                ok=0;
            else
            {
                ans.push_back(make_pair(X1,Y1));
            }
        }
        if(ok==0) break;
    }

    if(PQ.size()!=q || ans.size()!=p ) ok=0;

    if(ok==0)
    {
        printf("NO\n");
        return 0;
    }

    printf("YES\n");
    for(i=0;i<ans.size();i++)
    {
        printf("%d %d\n",ans[i].first,ans[i].second);
    }

    return 0;
}


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<ctime>
#include<assert.h>

#include<cmath>
#include<iostream>
#include<fstream>

#include<string>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<sstream>
#include<stack>
#include<limits.h>

using namespace std;
#define asdf exit(0);

typedef long long LL;

LL min(LL a,LL b)
{
    if(a<=b) return a;
    else return b;
}

#define Max 100010
int cs;
int parent[Max],rank[Max];
struct edge
{
    int source,dest;
    LL cost;
} e[Max];

LL dp[Max];

set<int> s;
struct cmp
{
    bool operator()(pair<LL,int> a,pair<LL,int> b)
    {
        return a.first>b.first;
    }
};
priority_queue< pair<LL,int> , vector< pair<LL,int> >, cmp > PQ;

vector< pair<int,int> > ans;

void link(int a,int b,LL w)   // just to decrease the time limit
{
    LL mn=w;
    //min(1000000000,dp[a]+dp[b]+1);
    if(rank[a]>rank[b])
    {
        parent[b]=a;
        dp[a]+=(dp[b]+mn);
        rank[a]+=rank[b];
    }
    else
    {
        dp[b]+=(dp[a]+mn);
        parent[a]=b;
        rank[b]+=rank[a];
    }
    return;
}

void link2(int a,int b)   // just to decrease the time limit
{
    LL mn=min( 1000000000,dp[a]+dp[b]+1);

    ans.push_back(make_pair(a,b));

    if(rank[a]>rank[b])
    {
        parent[b]=a;
        dp[a]=mn;
        rank[a]+=rank[b];

        PQ.push(make_pair(dp[a],a));

    }
    else
    {
        dp[b]=mn;
        parent[a]=b;
        rank[b]+=rank[a];

        PQ.push(make_pair(dp[b],b));
    }
    return;
}

////finding the root of set
int find_set(int a)
{
    if(a!=parent[a])
        parent[a]=find_set(parent[a]);
    return parent[a];
}
//sorting edges in increasing order
bool operator<(edge a,edge b)
{
    return a.cost<b.cost;
}

int main()
{
    int t,i,j,k,n,u,v,m,p,q;

    int X1,Y1;
    int got=0;

    //freopen("in.txt","r",stdin);
    //freopen("road.in","r",stdin);

    scanf("%d %d %d %d",&n,&m,&p,&q);

    for(i=0; i<n; i++)
    {
        parent[i]=i;
        rank[i]=1;
    }

    for(i=0; i<m; i++)
    {
        scanf("%d %d %I64d",&e[i].source,&e[i].dest,&e[i].cost);
        e[i].source--;
        e[i].dest--;

        got=1;
        X1=e[i].source;
        Y1=e[i].dest;

        u=find_set(e[i].source);
        v=find_set(e[i].dest);
        if(u!=v)
        {
            link(u,v,e[i].cost);
        }
        else
        {
            dp[u]+=e[i].cost;
        }
    }

    for(i=0;i<n;i++) s.insert(find_set(i));

    for(set<int>::iterator it=s.begin();it!=s.end();it++)
    {
    //  printf("%I64d\n",dp[*it]);
        PQ.push(make_pair(dp[*it],*it));
    }

    int ok=1;

    pair<int,int> f1,f2;
    for(i=0;i<p;i++)
    {
        if(PQ.size()>q)
        {
            f1=PQ.top();PQ.pop();
            f2=PQ.top();PQ.pop();

            link2(f1.second,f2.second);

            got=1;
            X1=f1.second;
            Y1=f2.second;

        }
        else
        {
            if(!got)
                ok=0;
            else
            {
                ans.push_back(make_pair(X1,Y1));
            }
        }
        if(ok==0) break;
    }

    if(PQ.size()!=q || ans.size()!=p ) ok=0;

    if(ok==0)
    {
        printf("NO\n");
        return 0;
    }

    printf("YES\n");
    for(i=0;i<ans.size();i++)
    {
        printf("%d %d\n",ans[i].first+1,ans[i].second+1);
    }

    return 0;
}


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<ctime>
#include<assert.h>

#include<cmath>
#include<iostream>
#include<fstream>

#include<string>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<sstream>
#include<stack>
#include<limits.h>

using namespace std;
#define asdf exit(0);

typedef long long LL;

LL min(LL a,LL b)
{
	if(a<=b) return a;
	else return b;
}

#define Max 100010
int cs;
int parent[Max],rank[Max];
struct edge
{
    int source,dest;
    LL cost;
} e[Max];

vector<int> adj[Max];
LL dp[Max];

set<int> s;
struct cmp
{
    bool operator()(pair<int,int> a,pair<int,int> b)
    {
        return a.first>b.first;
    }
};
priority_queue< pair<int,int> , vector< pair<int,int> >, cmp > PQ;

vector< pair<int,int> > ans;

void link(int a,int b,LL w)   // just to decrease the time limit
{
    LL mn=w;
    //min(1000000000,dp[a]+dp[b]+1);
    if(rank[a]>rank[b])
    {
        parent[b]=a;
        dp[a]+=(dp[b]+mn);
        rank[a]+=rank[b];
    }
    else
    {
        dp[b]+=(dp[a]+mn);
        parent[a]=b;
        rank[b]+=rank[a];
    }
    return;
}

void link2(int a,int b)   // just to decrease the time limit
{
    LL mn=min( 1000000000,dp[a]+dp[b]+1);

	ans.push_back(make_pair(a,b));

    if(rank[a]>rank[b])
    {
        parent[b]=a;
        dp[a]=mn;
        rank[a]+=rank[b];

		PQ.push(make_pair(dp[a],a));

    }
    else
    {
        dp[b]=mn;
        parent[a]=b;
        rank[b]+=rank[a];

		PQ.push(make_pair(dp[b],b));
    }
    return;
}

////finding the root of set
int find_set(int a)
{
    if(a!=parent[a])
        parent[a]=find_set(parent[a]);
    return parent[a];
}
//sorting edges in increasing order
bool operator<(edge a,edge b)
{
    return a.cost<b.cost;
}

void dfs(int u)
{
    int i,v;
    for(i=0;i<adj[u].size();i++)
    {
        v=adj[u][i];
        dp[v]+=dp[u];
        dfs(v);
    }
}

int main()
{
    int t,i,j,k,n,u,v,m,p,q;

    int X1,Y1;
    int got=0;

	//freopen("in.txt","r",stdin);
	//freopen("road.in","r",stdin);

    scanf("%d %d %d %d",&n,&m,&p,&q);

    for(i=0; i<n; i++)
    {
        parent[i]=i;
        rank[i]=1;
    }

    for(i=0; i<m; i++)
    {
        scanf("%d %d %I64d",&e[i].source,&e[i].dest,&e[i].cost);
        e[i].source--;
        e[i].dest--;

        got=1;
        X1=e[i].source;
        Y1=e[i].dest;

        u=find_set(e[i].source);
        v=find_set(e[i].dest);
        if(u!=v)
        {
            link(u,v,e[i].cost);
        }
        else
        {
            dp[u]+=e[i].cost;
        }
    }

    for(i=0;i<n;i++) s.insert(find_set(i));

    for(set<int>::iterator it=s.begin();it!=s.end();it++)
    {
	//	printf("%I64d\n",dp[*it]);
        PQ.push(make_pair(dp[*it],*it));
    }

    int ok=1;

    pair<int,int> f1,f2;
    for(i=0;i<p;i++)
    {
        if(PQ.size()>q)
        {
            f1=PQ.top();PQ.pop();
            f2=PQ.top();PQ.pop();

            link2(f1.second,f2.second);

            got=1;
            X1=f1.second;
            Y1=f2.second;

        }
        else
        {
            if(!got)
                ok=0;
            else
            {
                ans.push_back(make_pair(X1,Y1));
            }
        }
        if(ok==0) break;
    }

    if(PQ.size()!=q || ans.size()!=p ) ok=0;

    if(ok==0)
    {
        printf("NO\n");
        return 0;
    }

    printf("YES\n");
    for(i=0;i<ans.size();i++)
    {
        printf("%d %d\n",ans[i].first+1,ans[i].second+1);
    }

    return 0;
}


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<ctime>
#include<assert.h>

#include<cmath>
#include<iostream>
#include<fstream>

#include<string>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<sstream>
#include<stack>
#include<limits.h>

using namespace std;
#define asdf exit(0);

typedef long long LL;

LL min(LL a,LL b)
{
	if(a<=b) return a;
	else return b;
}

#define Max 100010
int cs;
int parent[Max],rank[Max];
struct edge
{
    int source,dest;
    LL cost;
} e[Max];

vector<int> adj[Max];
LL dp[Max];

set<int> s;
struct cmp
{
    bool operator()(pair<int,int> a,pair<int,int> b)
    {
        return a.first>b.first;
    }
};
priority_queue< pair<int,int> , vector< pair<int,int> >, cmp > PQ;

vector< pair<int,int> > ans;

void link(int a,int b,LL w)   // just to decrease the time limit
{
    LL mn=w;
    //min(1000000000,dp[a]+dp[b]+1);
    if(rank[a]>rank[b])
    {
        parent[b]=a;
        dp[a]+=(dp[b]+mn);
        rank[a]+=rank[b];
    }
    else
    {
        dp[b]+=(dp[a]+mn);
        parent[a]=b;
        rank[b]+=rank[a];
    }
    return;
}

void link2(int a,int b)   // just to decrease the time limit
{
    LL mn=min( 1000000000,dp[a]+dp[b]+1);

	ans.push_back(make_pair(a,b));

    if(rank[a]>rank[b])
    {
        parent[b]=a;
        dp[a]+=(dp[b]+mn);
        rank[a]+=rank[b];

		PQ.push(make_pair(dp[a],a));

    }
    else
    {
        dp[b]+=(dp[a]+mn);
        parent[a]=b;
        rank[b]+=rank[a];

		PQ.push(make_pair(dp[b],b));
    }
    return;
}

////finding the root of set
int find_set(int a)
{
    if(a!=parent[a])
        parent[a]=find_set(parent[a]);
    return parent[a];
}
//sorting edges in increasing order
bool operator<(edge a,edge b)
{
    return a.cost<b.cost;
}

void dfs(int u)
{
    int i,v;
    for(i=0;i<adj[u].size();i++)
    {
        v=adj[u][i];
        dp[v]+=dp[u];
        dfs(v);
    }
}

int main()
{
    int t,i,j,k,n,u,v,m,p,q;

    int X1,Y1;
    int got=0;

	//freopen("in.txt","r",stdin);
	//freopen("road.in","r",stdin);

    scanf("%d %d %d %d",&n,&m,&p,&q);

    for(i=0; i<n; i++)
    {
        parent[i]=i;
        rank[i]=1;
    }

    for(i=0; i<m; i++)
    {
        scanf("%d %d %I64d",&e[i].source,&e[i].dest,&e[i].cost);
        e[i].source--;
        e[i].dest--;

        got=1;
        X1=e[i].source;
        Y1=e[i].dest;

        u=find_set(e[i].source);
        v=find_set(e[i].dest);
        if(u!=v)
        {
            link(u,v,e[i].cost);
        }
        else
        {
            dp[u]+=e[i].cost;
        }
    }

    for(i=0;i<n;i++) s.insert(find_set(i));

    for(set<int>::iterator it=s.begin();it!=s.end();it++)
    {
	//	printf("%I64d\n",dp[*it]);
        PQ.push(make_pair(dp[*it],*it));
    }

    int ok=1;

    pair<int,int> f1,f2;
    for(i=0;i<p;i++)
    {
        if(PQ.size()>q)
        {
            f1=PQ.top();PQ.pop();
            f2=PQ.top();PQ.pop();

            link2(f1.second,f2.second);

            got=1;
            X1=f1.second;
            Y1=f2.second;

        }
        else
        {
            if(!got)
                ok=0;
            else
            {
                ans.push_back(make_pair(X1,Y1));
            }
        }
        if(ok==0) break;
    }

    if(PQ.size()!=q || ans.size()!=p ) ok=0;

    if(ok==0)
    {
        printf("NO\n");
        return 0;
    }

    printf("YES\n");
    for(i=0;i<ans.size();i++)
    {
        printf("%d %d\n",ans[i].first,ans[i].second);
    }

    return 0;
}


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<ctime>
#include<assert.h>

#include<cmath>
#include<iostream>
#include<fstream>

#include<string>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<sstream>
#include<stack>
#include<limits.h>

using namespace std;
#define asdf exit(0);

typedef long long LL;

LL min(LL a,LL b)
{
	if(a<=b) return a;
	else return b;
}

#define Max 100010
int cs;
int parent[Max],rank[Max];
struct edge
{
    int source,dest;
    LL cost;
} e[Max];

LL dp[Max];

set<int> s;
struct cmp
{
    bool operator()(pair<LL,int> a,pair<LL,int> b)
    {
        return a.first>b.first;
    }
};
priority_queue< pair<LL,int> , vector< pair<LL,int> >, cmp > PQ;

vector< pair<int,int> > ans;

void link(int a,int b,LL w)   // just to decrease the time limit
{
    LL mn=w;
    //min(1000000000,dp[a]+dp[b]+1);
    if(rank[a]>rank[b])
    {
        parent[b]=a;
        dp[a]+=(dp[b]+mn);
        rank[a]+=rank[b];
    }
    else
    {
        dp[b]+=(dp[a]+mn);
        parent[a]=b;
        rank[b]+=rank[a];
    }
    return;
}

void link2(int a,int b)   // just to decrease the time limit
{
    LL mn=min( 1000000000,dp[a]+dp[b]+1);

	ans.push_back(make_pair(a,b));

    if(rank[a]>rank[b])
    {
        parent[b]=a;
        dp[a]+=(mn+dp[b]);
        rank[a]+=rank[b];

		PQ.push(make_pair(dp[a],a));

    }
    else
    {
        dp[b]+=(dp[a]+mn);
        parent[a]=b;
        rank[b]+=rank[a];

		PQ.push(make_pair(dp[b],b));
    }
    return;
}

////finding the root of set
int find_set(int a)
{
    if(a!=parent[a])
        parent[a]=find_set(parent[a]);
    return parent[a];
}
//sorting edges in increasing order
bool operator<(edge a,edge b)
{
    return a.cost<b.cost;
}

int main()
{
    int t,i,j,k,n,u,v,m,p,q;

    int X1,Y1;
    int got=0;

	//freopen("in.txt","r",stdin);
	//freopen("road.in","r",stdin);

    scanf("%d %d %d %d",&n,&m,&p,&q);

    for(i=0; i<n; i++)
    {
        parent[i]=i;
        rank[i]=1;
    }

    for(i=0; i<m; i++)
    {
        scanf("%d %d %I64d",&e[i].source,&e[i].dest,&e[i].cost);
        e[i].source--;
        e[i].dest--;

        got=1;
        X1=e[i].source;
        Y1=e[i].dest;

        u=find_set(e[i].source);
        v=find_set(e[i].dest);
        if(u!=v)
        {
            link(u,v,e[i].cost);
        }
        else
        {
            dp[u]+=e[i].cost;
        }
    }

    for(i=0;i<n;i++) s.insert(find_set(i));

    for(set<int>::iterator it=s.begin();it!=s.end();it++)
    {
	//	printf("%I64d\n",dp[*it]);
        PQ.push(make_pair(dp[*it],*it));
    }

    int ok=1;

    pair<LL,int> f1,f2;
    for(i=0;i<p;i++)
    {
        if(PQ.size()>q)
        {
            f1=PQ.top();PQ.pop();
            f2=PQ.top();PQ.pop();

            link2(f1.second,f2.second);

            got=1;
            X1=f1.second;
            Y1=f2.second;

        }
        else if(PQ.size()==q)
        {
            if(!got) ok=0;
            else
            {
                ans.push_back(make_pair(X1,Y1));
            }
        }
        else ok=0;

        if(ok==0) break;
    }

    if(PQ.size()!=q || ans.size()!=p ) ok=0;

    if(ok==0)
    {
        printf("NO\n");
        return 0;
    }

    printf("YES\n");
    for(i=0;i<ans.size();i++)
    {
        printf("%d %d\n",ans[i].first+1,ans[i].second+1);
    }

    return 0;
}


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<ctime>
#include<assert.h>

#include<cmath>
#include<iostream>
#include<fstream>

#include<string>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<sstream>
#include<stack>
#include<limits.h>

using namespace std;
#define asdf exit(0);

typedef long long LL;

LL min(LL a,LL b)
{
    if(a<=b) return a;
    else return b;
}

#define Max 100010
int cs;
int parent[Max],rank[Max];
struct edge
{
    int source,dest;
    LL cost;
} e[Max];

vector<int> adj[Max];
LL dp[Max];

set<int> s;
struct cmp
{
    bool operator()(pair<int,int> a,pair<int,int> b)
    {
        return a.first>b.first;
    }
};
priority_queue< pair<int,int> , vector< pair<int,int> >, cmp > PQ;

vector< pair<int,int> > ans;

void link(int a,int b,LL w)   // just to decrease the time limit
{
    LL mn=w;
    //min(1000000000,dp[a]+dp[b]+1);
    if(rank[a]>rank[b])
    {
        parent[b]=a;
        dp[a]+=(dp[b]+mn);
        rank[a]+=rank[b];
    }
    else
    {
        dp[b]+=(dp[a]+mn);
        parent[a]=b;
        rank[b]+=rank[a];
    }
    return;
}

void link2(int a,int b)   // just to decrease the time limit
{
    LL mn=min( 1000000000,dp[a]+dp[b]+1);

    ans.push_back(make_pair(a,b));

    if(rank[a]>rank[b])
    {
        parent[b]=a;
        dp[a]+=(dp[b]+mn);
        rank[a]+=rank[b];

        PQ.push(make_pair(dp[a],a));

    }
    else
    {
        dp[b]+=(dp[a]+mn);
        parent[a]=b;
        rank[b]+=rank[a];

        PQ.push(make_pair(dp[b],b));
    }
    return;
}

////finding the root of set
int find_set(int a)
{
    if(a!=parent[a])
        parent[a]=find_set(parent[a]);
    return parent[a];
}
//sorting edges in increasing order
bool operator<(edge a,edge b)
{
    return a.cost<b.cost;
}

void dfs(int u)
{
    int i,v;
    for(i=0;i<adj[u].size();i++)
    {
        v=adj[u][i];
        dp[v]+=dp[u];
        dfs(v);
    }
}

int main()
{
    int t,i,j,k,n,u,v,m,p,q;

    int X1,Y1;
    int got=0;

    //freopen("in.txt","r",stdin);
    //freopen("road.in","r",stdin);

    scanf("%d %d %d %d",&n,&m,&p,&q);

    for(i=0; i<n; i++)
    {
        parent[i]=i;
        rank[i]=1;
    }

    for(i=0; i<m; i++)
    {
        scanf("%d %d %I64d",&e[i].source,&e[i].dest,&e[i].cost);
        e[i].source--;
        e[i].dest--;

        got=1;
        X1=e[i].source;
        Y1=e[i].dest;

        u=find_set(e[i].source);
        v=find_set(e[i].dest);
        if(u!=v)
        {
            link(u,v,e[i].cost);
        }
        else
        {
            dp[u]+=e[i].cost;
        }
    }

    for(i=0;i<n;i++) s.insert(find_set(i));

    for(set<int>::iterator it=s.begin();it!=s.end();it++)
    {
    //  printf("%I64d\n",dp[*it]);
        PQ.push(make_pair(dp[*it],*it));
    }

    int ok=1;

    pair<int,int> f1,f2;
    for(i=0;i<p;i++)
    {
        if(PQ.size()>q)
        {
            f1=PQ.top();PQ.pop();
            f2=PQ.top();PQ.pop();

            link2(f1.second,f2.second);

            got=1;
            X1=f1.second;
            Y1=f2.second;

        }
        else
        {
            if(!got)
                ok=0;
            else
            {
                ans.push_back(make_pair(X1,Y1));
            }
        }
        if(ok==0) break;
    }

    if(PQ.size()!=q || ans.size()!=p ) ok=0;

    if(ok==0)
    {
        printf("NO\n");
        return 0;
    }

    printf("YES\n");
    for(i=0;i<ans.size();i++)
    {
        printf("%d %d\n",ans[i].first+1,ans[i].second+1);
    }

    return 0;
}


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<ctime>
#include<assert.h>

#include<cmath>
#include<iostream>
#include<fstream>

#include<string>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<sstream>
#include<stack>
#include<limits.h>

using namespace std;
#define asdf exit(0);

typedef long long LL;

LL min(LL a,LL b)
{
    if(a<=b) return a;
    else return b;
}

#define Max 100010
int cs;
int parent[Max],rank[Max];
struct edge
{
    int source,dest;
    LL cost;
} e[Max];

LL dp[Max];

set<int> s;
struct cmp
{
    bool operator()(pair<LL,int> a,pair<LL,int> b)
    {
        return a.first>b.first;
    }
};
priority_queue< pair<LL,int> , vector< pair<LL,int> >, cmp > PQ;

vector< pair<int,int> > ans;

void link(int a,int b,LL w)   // just to decrease the time limit
{
    LL mn=w;
    //min(1000000000,dp[a]+dp[b]+1);
    if(rank[a]>rank[b])
    {
        parent[b]=a;
        dp[a]+=(dp[b]+mn);
        rank[a]+=rank[b];
    }
    else
    {
        dp[b]+=(dp[a]+mn);
        parent[a]=b;
        rank[b]+=rank[a];
    }
    return;
}

void link2(int a,int b)   // just to decrease the time limit
{
    LL mn=min( 1000000000,dp[a]+dp[b]+1);

    ans.push_back(make_pair(a,b));

    if(rank[a]>rank[b])
    {
        parent[b]=a;
        dp[a]=mn;
        rank[a]+=rank[b];

        PQ.push(make_pair(dp[a],a));

    }
    else
    {
        dp[b]=mn;
        parent[a]=b;
        rank[b]+=rank[a];

        PQ.push(make_pair(dp[b],b));
    }
    return;
}

////finding the root of set
int find_set(int a)
{
    if(a!=parent[a])
        parent[a]=find_set(parent[a]);
    return parent[a];
}
//sorting edges in increasing order
bool operator<(edge a,edge b)
{
    return a.cost<b.cost;
}

int main()
{
    int t,i,j,k,n,u,v,m,p,q;

    int X1,Y1;
    int got=0;

    //freopen("in.txt","r",stdin);
    //freopen("road.in","r",stdin);

    scanf("%d %d %d %d",&n,&m,&p,&q);

    for(i=0; i<n; i++)
    {
        parent[i]=i;
        rank[i]=1;
    }

    for(i=0; i<m; i++)
    {
        scanf("%d %d %I64d",&e[i].source,&e[i].dest,&e[i].cost);
        e[i].source--;
        e[i].dest--;

        got=1;
        X1=e[i].source;
        Y1=e[i].dest;

        u=find_set(e[i].source);
        v=find_set(e[i].dest);
        if(u!=v)
        {
            link(u,v,e[i].cost);
        }
        else
        {
            dp[u]+=e[i].cost;
        }
    }

    for(i=0;i<n;i++) s.insert(find_set(i));

    for(set<int>::iterator it=s.begin();it!=s.end();it++)
    {
    //  printf("%I64d\n",dp[*it]);
        PQ.push(make_pair(dp[*it],*it));
    }

    int ok=1;

    pair<LL,int> f1,f2;
    for(i=0;i<p;i++)
    {
        if(PQ.size()>q)
        {
            f1=PQ.top();PQ.pop();
            f2=PQ.top();PQ.pop();

            link2(f1.second,f2.second);

            got=1;
            X1=f1.second;
            Y1=f2.second;

        }
        else if(PQ.size()==q)
        {
            if(!got) ok=0;
            else
            {
                ans.push_back(make_pair(X1,Y1));
            }
        }
        else ok=0;

        if(ok==0) break;
    }

    if(PQ.size()!=q || ans.size()!=p ) ok=0;

    if(ok==0)
    {
        printf("NO\n");
        return 0;
    }

    printf("YES\n");
    for(i=0;i<ans.size();i++)
    {
        printf("%d %d\n",ans[i].first+1,ans[i].second+1);
    }

    return 0;
}


#include <bits/stdc++.h>

#define foreach(it,v) \
  for (__typeof((v).begin()) it=(v).begin(); it!=(v).end(); ++it)

using namespace std;

const long long INF = (long long)(1000000000);
const int maxn = 100010;

int N, M, P, Q;

int total, p[maxn], rank[maxn], size[maxn];
long long sum[maxn];
vector< pair<int,int> > ans;
set< pair<long long, int> > regions;

int init(int n) {
  for (int i = 0; i < n; i++) {
    p[i] = i;
    rank[i] = 0;
    sum[i] = 0;
    size[i] = 1;
  }
}

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

void unite(int x, int y, long long e) {
  int px = find(x);
  int py = find(y);

  if (px == py) {
    sum[px] += e;
    return;
  }

  total--;
  if (rank[px] < rank[py]) {
    p[px] = py;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[py] += sum[px] + e;
    size[py] += size[px];
    regions.insert(make_pair(sum[py], py));
  }
  else {
    p[py] = px;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[px] += sum[px] + e;
    size[px] += size[py];
    regions.insert(make_pair(sum[px], px));

    if (rank[px] == rank[py])
      rank[px]++;
  }
}

int count_sets(int n) {
  regions.clear();
  for (int i = 0; i < n; i++)
    regions.insert(make_pair(sum[find(i)], find(i)));
  return regions.size();
}

bool solve() {
  if (regions.size() < Q)
    return false;

  if (M == 0 && regions.size() == Q && P > 0)
    return false;

  set< pair<long long,int> >::iterator it;
  bool first = true;
  int u = -1, v = -1;
  while (P > 0) {
    P--;

    if (regions.size() == Q) {
      if (first) {
        first = false;
        for (u = 0; u < N; u++)
          if (size[find(u)] > 1)
            break;
        u = find(u);
        for (v = 1; v < N; v++)
          if (find(v) == u && v != u)
            break;
      }
      ans.push_back(make_pair(u+1, v+1));
      continue;
    }

    it = regions.begin();
    u = it->second;
    it++;
    v = it->second;
    unite(u, v, min(INF, sum[u]+sum[v]+1));
    ans.push_back(make_pair(u+1, v+1));
  }

  return regions.size() == Q;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  cin >> N >> M >> P >> Q;

  init(N);
  for (int i = 0, u, v, e; i < M; i++) {
    cin >> u >> v >> e;
    unite(u-1, v-1, e);
  }
  total = count_sets(N);

  if (!solve())
    cout << "NO\n";
  else {
    cout << "YES\n";
    for (int i = 0; i < ans.size(); i++)
      cout << ans[i].first << ' ' << ans[i].second << '\n';
  }

  return 0;
}


#include <bits/stdc++.h>

#define foreach(it,v) \
  for (__typeof((v).begin()) it=(v).begin(); it!=(v).end(); ++it)

using namespace std;

const long long INF = (long long)(1e9);
const int maxn = 100010;

int N, M, P, Q;

int total, p[maxn], rank[maxn], size[maxn];
long long sum[maxn];
vector< pair<int,int> > ans;
set< pair<int, int> > regions;

int init(int n) {
  for (int i = 0; i < n; i++) {
    p[i] = i;
    rank[i] = 0;
    sum[i] = 0;
    size[i] = 1;
  }
}

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

void unite(int x, int y, long long e) {
  int px = find(x);
  int py = find(y);

  if (px == py) {
    sum[px] += e;
    return;
  }

  total--;
  if (rank[px] < rank[py]) {
    p[px] = py;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[py] += sum[px] + e;
    size[py] += size[px];
    regions.insert(make_pair(sum[py], py));
  }
  else {
    p[py] = px;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[px] += sum[px] + e;
    size[px] += size[py];
    regions.insert(make_pair(sum[px], px));

    if (rank[px] == rank[py])
      rank[px]++;
  }
}

int count_sets(int n) {
  regions.clear();
  for (int i = 0; i < n; i++)
    regions.insert(make_pair(sum[find(i)], find(i)));
  return regions.size();
}

bool solve() {
  if (regions.size() < Q)
    return false;

  if (M == 0 && P > 0)
    return false;

  set< pair<int,int> >::iterator it;
  bool first = true;
  int u = -1, v = -1;
  while (P > 0) {
    P--;

    if (regions.size() == Q) {
      if (first) {
        first = false;
        for (u = 0; u < N; u++)
          if (size[find(u)] > 1)
            break;
        u = find(u);
        for (v = 1; v < N; v++)
          if (find(v) == u && v != u)
            break;
      }
      assert(0 <= u && u < N && 0 <= v && v < N);
      ans.push_back(make_pair(u+1, v+1));
      continue;
    }

    it = regions.begin();
    u = it->second;
    it++;
    v = it->second;
    unite(u, v, min(INF, sum[u]+sum[v]+1));
    ans.push_back(make_pair(u+1, v+1));
  }

  return regions.size() == Q;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  cin >> N >> M >> P >> Q;

  init(N);
  for (int i = 0, u, v, e; i < M; i++) {
    cin >> u >> v >> e;
    unite(u-1, v-1, e);
  }
  total = count_sets(N);

  if (!solve())
    cout << "NO\n";
  else {
    cout << "YES\n";
    for (int i = 0; i < ans.size(); i++)
      cout << ans[i].first << ' ' << ans[i].second << '\n';
  }

  return 0;
}


#include <bits/stdc++.h>

#define foreach(it,v) \
  for (__typeof((v).begin()) it=(v).begin(); it!=(v).end(); ++it)

using namespace std;

const long long INF = (long long)(1000000000);
const int maxn = 100010;

int N, M, P, Q;

int total, p[maxn], rank[maxn], size[maxn];
long long sum[maxn];
vector< pair<int,int> > ans;
set< pair<long long, int> > regions;

int init(int n) {
  for (int i = 0; i < n; i++) {
    p[i] = i;
    rank[i] = 0;
    sum[i] = 0;
    size[i] = 1;
  }
}

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

void unite(int x, int y, long long e) {
  int px = find(x);
  int py = find(y);

  if (px == py) {
    sum[px] += e;
    return;
  }

  total--;
  if (rank[px] < rank[py]) {
    p[px] = py;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[py] += sum[px] + e;
    size[py] += size[px];
    regions.insert(make_pair(sum[py], py));
  }
  else {
    p[py] = px;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[px] += sum[py] + e;
    size[px] += size[py];
    regions.insert(make_pair(sum[px], px));

    if (rank[px] == rank[py])
      rank[px]++;
  }
}

int count_sets(int n) {
  regions.clear();
  for (int i = 0; i < n; i++)
    regions.insert(make_pair(sum[find(i)], find(i)));
  return regions.size();
}

bool solve() {
  if (regions.size() < Q)
    return false;

  if (M == 0 && regions.size() == Q && P > 0)
    return false;

  set< pair<long long,int> >::iterator it;
  bool first = true;
  int u = -1, v = -1;
  while (P > 0) {
    P--;

    if (regions.size() == Q) {
      if (first) {
        first = false;
        for (u = 0; u < N; u++)
          if (size[find(u)] > 1)
            break;
        u = find(u);
        for (v = 0; v < N; v++)
          if (find(v) == u && v != u)
            break;
      }
      assert(0 <= u && u < N && 0 <= v && v < N);
      ans.push_back(make_pair(u+1, v+1));
      continue;
    }

    it = regions.begin();
    u = it->second;
    it++;
    v = it->second;
    unite(u, v, min(INF, sum[u]+sum[v]+1));
    ans.push_back(make_pair(u+1, v+1));
  }

  return regions.size() == Q;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  cin >> N >> M >> P >> Q;

  init(N);
  for (int i = 0, u, v, e; i < M; i++) {
    cin >> u >> v >> e;
    unite(u-1, v-1, e);
  }
  total = count_sets(N);

  if (!solve())
    cout << "NO\n";
  else {
    cout << "YES\n";
    for (int i = 0; i < ans.size(); i++)
      cout << ans[i].first << ' ' << ans[i].second << '\n';
  }

  return 0;
}


#include <bits/stdc++.h>

#define foreach(it,v) \
  for (__typeof((v).begin()) it=(v).begin(); it!=(v).end(); ++it)

using namespace std;

const long long INF = (long long)(1000000000);
const int maxn = 100010;

int N, M, P, Q;

int total, p[maxn], rank[maxn], size[maxn];
long long sum[maxn];
vector< pair<int,int> > ans;
set< pair<long long, int> > regions;

int init(int n) {
  for (int i = 0; i < n; i++) {
    p[i] = i;
    rank[i] = 0;
    sum[i] = 0;
    size[i] = 1;
  }
}

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

void unite(int x, int y, long long e) {
  int px = find(x);
  int py = find(y);

  if (px == py) {
    sum[px] += e;
    return;
  }

  total--;
  if (rank[px] < rank[py]) {
    p[px] = py;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[py] += sum[px] + e;
    size[py] += size[px];
    regions.insert(make_pair(sum[py], py));
  }
  else {
    p[py] = px;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[px] += sum[px] + e;
    size[px] += size[py];
    regions.insert(make_pair(sum[px], px));

    if (rank[px] == rank[py])
      rank[px]++;
  }
}

int count_sets(int n) {
  regions.clear();
  for (int i = 0; i < n; i++)
    regions.insert(make_pair(sum[find(i)], find(i)));
  return regions.size();
}

bool solve() {
  if (regions.size() < Q)
    return false;

  if (M == 0 && regions.size() == Q && P > 0)
    return false;

  set< pair<long long,int> >::iterator it;
  bool first = true;
  int u = -1, v = -1;
  while (P > 0) {
    P--;

    if (regions.size() == Q) {
      if (first) {
        first = false;
        for (u = 0; u < N; u++)
          if (size[find(u)] > 1)
            break;
        u = find(u);
        for (v = 0; v < N; v++)
          if (find(v) == u && v != u)
            break;
      }
      assert(0 <= u && u < N && 0 <= v && v < N);
      ans.push_back(make_pair(u+1, v+1));
      continue;
    }

    it = regions.begin();
    u = it->second;
    it++;
    v = it->second;
    unite(u, v, min(INF, sum[u]+sum[v]+1));
    ans.push_back(make_pair(u+1, v+1));
  }

  return regions.size() == Q;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  cin >> N >> M >> P >> Q;

  init(N);
  for (int i = 0, u, v, e; i < M; i++) {
    cin >> u >> v >> e;
    unite(u-1, v-1, e);
  }
  total = count_sets(N);

  if (!solve())
    cout << "NO\n";
  else {
    cout << "YES\n";
    for (int i = 0; i < ans.size(); i++)
      cout << ans[i].first << ' ' << ans[i].second << '\n';
  }

  return 0;
}


#include <bits/stdc++.h>

#define foreach(it,v) \
  for (__typeof((v).begin()) it=(v).begin(); it!=(v).end(); ++it)

using namespace std;

const long long INF = (long long)(1e9);
const int maxn = 100010;

int N, M, P, Q;

int total, p[maxn], rank[maxn];
long long sum[maxn];
vector< pair<int,int> > ans;
set< pair<int, int> > regions;

int init(int n) {
  for (int i = 0; i < n; i++) {
    p[i] = i;
    rank[i] = 0;
    sum[i] = 0;
  }
}

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

void unite(int x, int y, long long e) {
  int px = find(x);
  int py = find(y);

  if (px == py) {
    sum[px] += e;
    return;
  }

  total--;
  if (rank[px] < rank[py]) {
    p[px] = py;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[py] += sum[px] + e;
    regions.insert(make_pair(sum[py], py));
  }
  else {
    p[py] = px;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[px] += sum[px] + e;
    regions.insert(make_pair(sum[px], px));

    if (rank[px] == rank[py])
      rank[px]++;
  }
}

int count_sets(int n) {
  regions.clear();
  for (int i = 0; i < n; i++)
    regions.insert(make_pair(sum[find(i)], find(i)));
  return regions.size();
}

bool solve() {
  if (total < Q)
    return false;

  set< pair<int,int> >::iterator it;
  while (P > 0) {
    it = regions.begin();
    int u = it->second;
    it++;
    int v = it->second;
    unite(u, v, min(INF, sum[u]+sum[v]+1));
    ans.push_back(make_pair(u+1, v+1));
    P--;
    if (total == Q)
      return true;
  }

  return total == Q;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  cin >> N >> M >> P >> Q;

  init(N);
  for (int i = 0, u, v, e; i < M; i++) {
    cin >> u >> v >> e;
    unite(u-1, v-1, e);
  }
  total = count_sets(N);

  if (!solve())
    cout << "NO\n";
  else {
    cout << "YES\n";
    for (int i = 0; i < ans.size(); i++)
      cout << ans[i].first << ' ' << ans[i].second << '\n';
  }

  return 0;
}


#include <bits/stdc++.h>

#define foreach(it,v) \
  for (__typeof((v).begin()) it=(v).begin(); it!=(v).end(); ++it)

using namespace std;

const long long INF = (long long)(1e9);
const int maxn = 100010;

int N, M, P, Q;

int total, p[maxn], rank[maxn], size[maxn];
long long sum[maxn];
vector< pair<int,int> > ans;
set< pair<int, int> > regions;

int init(int n) {
  for (int i = 0; i < n; i++) {
    p[i] = i;
    rank[i] = 0;
    sum[i] = 0;
    size[i] = 1;
  }
}

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

void unite(int x, int y, long long e) {
  int px = find(x);
  int py = find(y);

  if (px == py) {
    sum[px] += e;
    return;
  }

  total--;
  if (rank[px] < rank[py]) {
    p[px] = py;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[py] += sum[px] + e;
    size[py] += size[px];
    regions.insert(make_pair(sum[py], py));
  }
  else {
    p[py] = px;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[px] += sum[px] + e;
    size[px] += size[py];
    regions.insert(make_pair(sum[px], px));

    if (rank[px] == rank[py])
      rank[px]++;
  }
}

int count_sets(int n) {
  regions.clear();
  for (int i = 0; i < n; i++)
    regions.insert(make_pair(sum[find(i)], find(i)));
  return regions.size();
}

bool solve() {
  if (regions.size() < Q)
    return false;

  if (M == 0 && regions.size() == Q && P > 0)
    return false;

  set< pair<int,int> >::iterator it;
  bool first = true;
  int u = -1, v = -1;
  while (P > 0) {
    P--;

    if (regions.size() == Q) {
      if (first) {
        first = false;
        for (u = 0; u < N; u++)
          if (size[find(u)] > 1)
            break;
        u = find(u);
        for (v = 1; v < N; v++)
          if (find(v) == u && v != u)
            break;
      }
      ans.push_back(make_pair(u+1, v+1));
      continue;
    }

    it = regions.begin();
    u = it->second;
    it++;
    v = it->second;
    unite(u, v, min(INF, sum[u]+sum[v]+1));
    ans.push_back(make_pair(u+1, v+1));
  }

  return regions.size() == Q;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  cin >> N >> M >> P >> Q;

  init(N);
  for (int i = 0, u, v, e; i < M; i++) {
    cin >> u >> v >> e;
    unite(u-1, v-1, e);
  }
  total = count_sets(N);

  if (!solve())
    cout << "NO\n";
  else {
    cout << "YES\n";
    for (int i = 0; i < ans.size(); i++)
      cout << ans[i].first << ' ' << ans[i].second << '\n';
  }

  return 0;
}


#include <bits/stdc++.h>

#define foreach(it,v) \
  for (__typeof((v).begin()) it=(v).begin(); it!=(v).end(); ++it)

using namespace std;

const long long INF = (long long)(1e9);
const int maxn = 100010;

int N, M, P, Q;

int total, p[maxn], rank[maxn];
long long sum[maxn];
vector< pair<int,int> > ans;
set< pair<int, int> > regions;

int init(int n) {
  for (int i = 0; i < n; i++) {
    p[i] = i;
    rank[i] = 0;
    sum[i] = 0;
  }
}

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

void unite(int x, int y, long long e) {
  int px = find(x);
  int py = find(y);

  if (px == py) {
    sum[px] += e;
    return;
  }

  total--;
  if (rank[px] < rank[py]) {
    p[px] = py;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[py] += sum[px] + e;
    regions.insert(make_pair(sum[py], py));
  }
  else {
    p[py] = px;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[px] += sum[px] + e;
    regions.insert(make_pair(sum[px], px));

    if (rank[px] == rank[py])
      rank[px]++;
  }
}

int count_sets(int n) {
  regions.clear();
  for (int i = 0; i < n; i++)
    regions.insert(make_pair(sum[find(i)], find(i)));
  return regions.size();
}

bool solve() {
  if (regions.size() < Q)
    return false;

  if (M == 0 && P > 0)
    return false;

  set< pair<int,int> >::iterator it;
  bool first = true;
  int u, v;
  while (P > 0) {
    P--;

    if (regions.size() == Q) {
      if (first) {
        first = false;
        u = find(0);
        for (v = 1; v < N; v++)
          if (find(v) == u)
            break;
      }
      ans.push_back(make_pair(u+1, v+1));
      continue;
    }

    it = regions.begin();
    u = it->second;
    it++;
    v = it->second;
    unite(u, v, min(INF, sum[u]+sum[v]+1));
    ans.push_back(make_pair(u+1, v+1));
  }

  return regions.size() == Q;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  cin >> N >> M >> P >> Q;

  init(N);
  for (int i = 0, u, v, e; i < M; i++) {
    cin >> u >> v >> e;
    unite(u-1, v-1, e);
  }
  total = count_sets(N);

  if (!solve())
    cout << "NO\n";
  else {
    cout << "YES\n";
    for (int i = 0; i < ans.size(); i++)
      cout << ans[i].first << ' ' << ans[i].second << '\n';
  }

  return 0;
}


#include <bits/stdc++.h>

#define foreach(it,v) \
  for (__typeof((v).begin()) it=(v).begin(); it!=(v).end(); ++it)

using namespace std;

const long long INF = (long long)(1000000000);
const int maxn = 100010;

int N, M, P, Q;

int total, p[maxn], rank[maxn], size[maxn];
long long sum[maxn];
vector< pair<int,int> > ans;
set< pair<long long, int> > regions;

int init(int n) {
  for (int i = 0; i < n; i++) {
    p[i] = i;
    rank[i] = 0;
    sum[i] = 0;
    size[i] = 1;
  }
}

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

void unite(int x, int y, long long e) {
  int px = find(x);
  int py = find(y);

  if (px == py) {
    sum[px] += e;
    return;
  }

  total--;
  if (rank[px] < rank[py]) {
    p[px] = py;
    sum[py] += sum[px] + e;
    size[py] += size[px];
    regions.insert(make_pair(sum[py], py));
  }
  else {
    p[py] = px;
    sum[px] += sum[py] + e;
    size[px] += size[py];
    regions.insert(make_pair(sum[px], px));

    if (rank[px] == rank[py])
      rank[px]++;
  }
}

int count_sets(int n) {
  regions.clear();
  for (int i = 0; i < n; i++)
    regions.insert(make_pair(sum[find(i)], find(i)));
  return regions.size();
}

bool solve() {
  if (regions.size() < Q)
    return false;

  if (M == 0 && regions.size() == Q && P > 0)
    return false;

  bool first = true;
  int u = -1, v = -1;
  while (P > 0) {
    P--;

    if (regions.size() == Q) {
      if (first) {
        first = false;
        for (u = 0; u < N; u++)
          if (size[find(u)] > 1)
            break;
        u = find(u);
        for (v = 0; v < N; v++)
          if (find(v) == u && v != u)
            break;
      }
      ans.push_back(make_pair(u+1, v+1));
      continue;
    }

    u = regions.begin()->second;
    regions.erase(regions.begin());
    v = regions.begin()->second;
    unite(u, v, min(INF, sum[u]+sum[v]+1));
    ans.push_back(make_pair(u+1, v+1));
  }

  return regions.size() == Q;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  cin >> N >> M >> P >> Q;

  init(N);
  for (int i = 0, u, v, e; i < M; i++) {
    cin >> u >> v >> e;
    unite(u-1, v-1, e);
  }
  total = count_sets(N);

  if (!solve())
    cout << "NO\n";
  else {
    cout << "YES\n";
    for (int i = 0; i < ans.size(); i++)
      cout << ans[i].first << ' ' << ans[i].second << '\n';
  }

  return 0;
}


#include <bits/stdc++.h>

#define foreach(it,v) \
  for (__typeof((v).begin()) it=(v).begin(); it!=(v).end(); ++it)

using namespace std;

const long long INF = (long long)(1e9);
const int maxn = 100010;

int N, M, P, Q;

int total, p[maxn], rank[maxn];
long long sum[maxn];
vector< pair<int,int> > ans;
set<int> regions;

int init(int n) {
  for (int i = 0; i < n; i++) {
    p[i] = i;
    rank[i] = 0;
    sum[i] = 0;
  }
}

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

void unite(int x, int y, long long e) {
  int px = find(x);
  int py = find(y);

  if (px == py) {
    sum[px] += e;
    return;
  }

  total--;
  if (rank[px] < rank[py]) {
    p[px] = py;
    sum[py] += sum[px] + e;
    regions.erase(px);
  }
  else {
    p[py] = px;
    sum[px] += sum[px] + e;
    regions.erase(py);

    if (rank[px] == rank[py])
      rank[px]++;
  }
}

int count_sets(int n) {
  for (int i = 0; i < n; i++)
    regions.insert(find(i));
  return regions.size();
}

bool solve() {
  if (total < Q)
    return false;

  set<int>::iterator it;
  while (P > 0) {
    it = regions.begin();
    int u = *it;
    it++;
    int v = *it;
    unite(u, v, min(INF, sum[u]+sum[v]+1));
    ans.push_back(make_pair(u+1, v+1));
    P--;
    if (total == Q)
      return true;
  }

  return total == Q;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  cin >> N >> M >> P >> Q;

  init(N);
  for (int i = 0, u, v, e; i < M; i++) {
    cin >> u >> v >> e;
    unite(u-1, v-1, e);
  }
  total = count_sets(N);

  if (!solve())
    cout << "NO\n";
  else {
    cout << "YES\n";
    for (int i = 0; i < ans.size(); i++)
      cout << ans[i].first << ' ' << ans[i].second << '\n';
  }

  return 0;
}


#include <bits/stdc++.h>

#define foreach(it,v) \
  for (__typeof((v).begin()) it=(v).begin(); it!=(v).end(); ++it)

using namespace std;

const long long INF = (long long)(1000000000);
const int maxn = 100010;

int N, M, P, Q;

int total, p[maxn], rank[maxn], size[maxn];
long long sum[maxn];
vector< pair<int,int> > ans;
set< pair<long long, int> > regions;

int init(int n) {
  for (int i = 0; i < n; i++) {
    p[i] = i;
    rank[i] = 0;
    sum[i] = 0;
    size[i] = 1;
  }
}

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

void unite(int x, int y, long long e) {
  int px = find(x);
  int py = find(y);

  if (px == py) {
    sum[px] += e;
    return;
  }

  total--;
  if (rank[px] < rank[py]) {
    p[px] = py;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[py] += sum[px] + e;
    size[py] += size[px];
    regions.insert(make_pair(sum[py], py));
  }
  else {
    p[py] = px;
    regions.erase(make_pair(sum[px], px));
    regions.erase(make_pair(sum[py], py));
    sum[px] += sum[py] + e;
    size[px] += size[py];
    regions.insert(make_pair(sum[px], px));

    if (rank[px] == rank[py])
      rank[px]++;
  }
}

int count_sets(int n) {
  regions.clear();
  for (int i = 0; i < n; i++)
    regions.insert(make_pair(sum[find(i)], find(i)));
  return regions.size();
}

bool solve() {
  if (regions.size() < Q)
    return false;

  if (M == 0 && regions.size() == Q && P > 0)
    return false;

  bool first = true;
  int u = -1, v = -1;
  while (P > 0) {
    P--;

    if (regions.size() == Q) {
      if (first) {
        first = false;
        for (u = 0; u < N; u++)
          if (size[find(u)] > 1)
            break;
        u = find(u);
        for (v = 0; v < N; v++)
          if (find(v) == u && v != u)
            break;
      }
      ans.push_back(make_pair(u+1, v+1));
      continue;
    }

    u = regions.begin()->second;
    regions.erase(regions.begin());
    v = regions.begin()->second;
    unite(u, v, min(INF, sum[u]+sum[v]+1));
    ans.push_back(make_pair(u+1, v+1));
  }

  return regions.size() == Q;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  cin >> N >> M >> P >> Q;

  init(N);
  for (int i = 0, u, v, e; i < M; i++) {
    cin >> u >> v >> e;
    unite(u-1, v-1, e);
  }
  total = count_sets(N);

  if (!solve())
    cout << "NO\n";
  else {
    cout << "YES\n";
    for (int i = 0; i < ans.size(); i++)
      cout << ans[i].first << ' ' << ans[i].second << '\n';
  }

  return 0;
}


#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 510000;
int fa[maxn], sum[maxn], asd[maxn];
int find(int x){
    if (fa[x] == x) return x;
    return fa[x] = find(fa[x]);
}
int aa[maxn];
struct Tzy{
    int x, y;
    bool  operator < (const Tzy b) const { return y < b.y; }
};
priority_queue<Tzy>head;
int num, n, m, Q, P;
void init(){
    scanf("%d%d%d%d", &n, &m, &P, &Q);
    for (int i = 1; i <= n; i ++) fa[i] = i;
    for (int i = 1; i <= m; i ++){
        int a = 0, b = 0, c = 0;
        scanf("%d%d%d", &a, &b, &c);
        int fax = find(a), fay = find(b);
        fa[fay] = fax; sum[a] += c, sum[b] += c;
    }
    for (int i = 1; i <= n; i ++){
        int fai = find(i);
        asd[fai] += sum[i];
        if (fai == i){
            num ++;
            aa[num] = i;
        }
    }
//  cout <<num <<endl;
    for (int i = 1; i <= num; i ++){
//      cout <<aa[i] <<' ' <<asd[aa[i]] / 2 <<endl;
        head.push((Tzy){aa[i], asd[aa[i]] / 2});
    }

}
int ans[maxn][2];
void work(){
    int ans1 = 0;
    for (int i = 1; i < Q - num; i ++){
        Tzy a = head.top(); head.pop();
        Tzy b = head.top(); head.pop();
        ans[++ ans1][0] = a.x, ans[ans1][1] = b.x;
        head.push((Tzy){a.x, a.y + b.y + min(a.y + b.y + 1, 1000000000)});
    }
    if (ans1 > P){
        puts("NO");
        return;
    }
    puts("YES");
    for (int i = 1; i <= ans1; i ++) printf("%d %d\n", ans[i][0], ans[i][1]);
    for (int i = 1; i <= n; i ++){
        int fai = find(i);
        if (fai == i) continue;
        for (int j = i + 1; j <= n; j ++){
            int faj = find(j);
            if (fai != faj){
                ans1 ++;
                printf("%d %d\n", i, j);
            }
            if (ans1 == Q) return;
        }
    }
}
int main(){
    init();
    work();
    return 0;
}


#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 510000;
typedef long long LL;
LL fa[maxn], sum[maxn], asd[maxn];
int find(int x){
    if (fa[x] == x) return x;
    return fa[x] = find(fa[x]);
}
int aa[maxn];
struct Tzy{
    int x; LL  y;
    bool  operator < (const Tzy b) const { return y > b.y; }
};
priority_queue<Tzy>head;
int num, n, m, Q, P;
void init(){
    scanf("%d%d%d%d", &n, &m, &P, &Q);
    for (int i = 1; i <= n; i ++) fa[i] = i;
    for (int i = 1; i <= m; i ++){
        int a = 0, b = 0, c = 0;
        scanf("%d%d%d", &a, &b, &c);
        int fax = find(a), fay = find(b);
        fa[fay] = fax; sum[a] += c, sum[b] += c;
    }
    for (int i = 1; i <= n; i ++){
        int fai = find(i);
        asd[fai] += sum[i];
        if (fai == i){
            num ++;
            aa[num] = i;
        }
    }
//  cout <<num <<endl;
    for (int i = 1; i <= num; i ++){
//      cout <<aa[i] <<' ' <<asd[aa[i]] / 2 <<endl;
        head.push((Tzy){aa[i], asd[aa[i]] / 2});
    }

}
int ans[maxn][2];
void work(){
    int ans1 = 0;
    if (num < Q){
        puts("NO");
        return;
    }
    for (int i = 1; i <= num - Q; i ++){
        Tzy a = head.top(); head.pop();
        Tzy b = head.top(); head.pop();
        ans[++ ans1][0] = a.x, ans[ans1][1] = b.x;
        head.push((Tzy){a.x, a.y + b.y + min(a.y + b.y + 1LL, 1000000000LL)});
        fa[b.x] = fa[a.x];
    }
    if (ans1 > P){
        puts("NO");
        return;
    }
//  puts("YES");    for (int i = 1; i <= n; i ++){
    int fai = find(1);
    for (int j = 2; j <= n; j ++){
        int faj = find(j);
        if (fai == faj)
            while (ans1 < P){
                ans[++ ans1][0] = 1;
                ans[ans1][1] = j;
            }

        if (ans1 == P) break;
    }
    if (ans1 != P){ puts("NO"); return;}
    puts("YES");
    for (int i = 1; i <= ans1; i ++) printf("%d %d\n", ans[i][0], ans[i][1]);
}
int main(){
    init();
    work();
    return 0;
}


#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 510000;
typedef long long LL;
LL fa[maxn], sum[maxn], asd[maxn];
int find(int x){
    if (fa[x] == x) return x;
    return fa[x] = find(fa[x]);
}
int aa[maxn];
struct Tzy{
    int x; LL  y;
    bool  operator < (const Tzy b) const { return y > b.y; }
};
priority_queue<Tzy>head;
int num, n, m, Q, P;
void init(){
    scanf("%d%d%d%d", &n, &m, &P, &Q);
    for (int i = 1; i <= n; i ++) fa[i] = i;
    for (int i = 1; i <= m; i ++){
        int a = 0, b = 0, c = 0;
        scanf("%d%d%d", &a, &b, &c);
        int fax = find(a), fay = find(b);
        fa[fay] = fax; sum[a] += c, sum[b] += c;
    }
    for (int i = 1; i <= n; i ++){
        int fai = find(i);
        asd[fai] += sum[i];
        if (fai == i){
            num ++;
            aa[num] = i;
        }
    }
//  cout <<num <<endl;
    for (int i = 1; i <= num; i ++){
//      cout <<aa[i] <<' ' <<asd[aa[i]] / 2 <<endl;
        head.push((Tzy){aa[i], asd[aa[i]] / 2});
    }

}
int ans[maxn][2];
void work(){
    int ans1 = 0;
    if (num < Q){
        puts("NO");
        return;
    }
    for (int i = 1; i <= num - Q; i ++){
        Tzy a = head.top(); head.pop();
        Tzy b = head.top(); head.pop();
        ans[++ ans1][0] = a.x, ans[ans1][1] = b.x;
        head.push((Tzy){a.x, a.y + b.y + min(a.y + b.y + 1LL, 1000000000LL)});
        fa[b.x] = fa[a.x];
    }
    if (ans1 > P){
        puts("NO");
        return;
    }
//  puts("YES");
    for (int i = 1; i <= n; i ++){
        int fai = find(i);
        for (int j = i + 1; j <= n; j ++){
            int faj = find(j);
            if (fai == faj)
                while (ans1 < P){
                    ans[++ ans1][0] = i;
                    ans[ans1][1] = j;
                }

            if (ans1 == P) break;
        }
    }
    if (ans1 != P){ puts("NO"); return;}
    puts("YES");
    for (int i = 1; i <= ans1; i ++) printf("%d %d\n", ans[i][0], ans[i][1]);
}
int main(){
    init();
    work();
    return 0;
}


#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 510000;
typedef long long LL;
LL fa[maxn], sum[maxn], asd[maxn], ss[maxn];
int find(int x){
    if (fa[x] == x) return x;
    return fa[x] = find(fa[x]);
}
int aa[maxn];
struct Tzy{
    int x; LL  y;
    bool  operator < (const Tzy b) const { return y > b.y; }
};
priority_queue<Tzy>head;
int num, n, m, Q, P;
void init(){
    scanf("%d%d%d%d", &n, &m, &P, &Q);
    for (int i = 1; i <= n; i ++) fa[i] = i;
    for (int i = 1; i <= m; i ++){
        int a = 0, b = 0, c = 0;
        scanf("%d%d%d", &a, &b, &c);
        int fax = find(a), fay = find(b);
        fa[fay] = fax; sum[a] += c, sum[b] += c;
    }
    for (int i = 1; i <= n; i ++){
        int fai = find(i);
        asd[fai] += sum[i];
        if (fai == i){
            num ++;
            aa[num] = i;
        }
    }
//  cout <<num <<endl;
    for (int i = 1; i <= num; i ++){
//      cout <<aa[i] <<' ' <<asd[aa[i]] / 2 <<endl;
        head.push((Tzy){aa[i], asd[aa[i]] / 2});
    }

}
int ans[maxn][2];
void work(){
    int ans1 = 0;
    if (num < Q){
        puts("NO");
        return;
    }
    for (int i = 1; i <= num - Q; i ++){
        Tzy a = head.top(); head.pop();
        Tzy b = head.top(); head.pop();
        ans[++ ans1][0] = a.x, ans[ans1][1] = b.x;
        head.push((Tzy){a.x, a.y + b.y + min(a.y + b.y + 1LL, 1000000000LL)});
        fa[b.x] = fa[a.x];
    }
    if (ans1 > P){
        puts("NO");
        return;
    }
//  puts("YES");    for (int i = 1; i <= n;  ++){
    for (int i = 1; i <= n;  i ++) ss[find(i)] ++;
    int maxx = 0, maxi = 0;
    for (int i = 1; i <= n; i ++)
        if (ss[i] > maxx) maxx = ss[i], maxi = i;

    int fai = find(maxi);
    for (int j = 1; j <= n; j ++){
        if (j == maxi) continue;
        int faj = find(j);
        if (fai == faj)
            while (ans1 < P){
                ans[++ ans1][0] = maxi;
                ans[ans1][1] = j;
            }

        if (ans1 == P) break;
    }
    if (ans1 != P){ puts("NO"); return;}
    puts("YES");
    for (int i = 1; i <= ans1; i ++) printf("%d %d\n", ans[i][0], ans[i][1]);
}
int main(){
    init();
    work();
    return 0;
}
/*
6 1 2 5
3 4 1000
*/


#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 510000;
typedef long long LL;
LL fa[maxn], sum[maxn], asd[maxn], ss[maxn];
int find(int x){
    if (fa[x] == x) return x;
    return fa[x] = find(fa[x]);
}
int aa[maxn];
struct Tzy{
    int x; LL  y;
    bool  operator < (const Tzy b) const { return y > b.y; }
};
priority_queue<Tzy>head;
int num, n, m, Q, P;
void init(){
    scanf("%d%d%d%d", &n, &m, &P, &Q);
    for (int i = 1; i <= n; i ++) fa[i] = i;
    for (int i = 1; i <= m; i ++){
        int a = 0, b = 0, c = 0;
        scanf("%d%d%d", &a, &b, &c);
        int fax = find(a), fay = find(b);
        fa[fay] = fax; sum[a] += c, sum[b] += c;
    }
    for (int i = 1; i <= n; i ++){
        int fai = find(i);
        asd[fai] += sum[i];
        if (fai == i){
            num ++;
            aa[num] = i;
        }
    }
    for (int i = 1; i <= num; i ++){
        head.push((Tzy){aa[i], asd[aa[i]] / 2});
    }

}
int ans[maxn][2];
void work(){
    int ans1 = 0;
    if (num < Q){
        puts("NO");
        return;
    }
    for (int i = 1; i <= num - Q; i ++){
        Tzy a = head.top(); head.pop();
        Tzy b = head.top(); head.pop();
        ans[++ ans1][0] = a.x, ans[ans1][1] = b.x;
        head.push((Tzy){a.x, a.y + b.y + min(a.y + b.y + 1LL, 1000000000LL)});
        fa[b.x] = fa[a.x];
    }
    if (ans1 > P){
        puts("NO");
        return;
    }
//  puts("YES");    for (int i = 1; i <= n;  ++){

    for (int j = 1; j <= n; j ++){
        int faj = find(j);
        if (j != faj)
            while (ans1 < P){
                ans[++ ans1][0] = faj;
                ans[ans1][1] = j;
            }
        if (ans1 == P) break;
    }
    if (ans1 != P){ puts("NO"); return;}
    puts("YES");
    for (int i = 1; i <= ans1; i ++) printf("%d %d\n", ans[i][0], ans[i][1]);
}
int main(){
    init();
    work();
    return 0;
}
/*
6 1 2 5
3 4 1000
*/