#include <cstdio>
#include <algorithm>
#include <vector>
#include <set>
#define NMAX 200009
using namespace std;
struct edge {
int x, y, c, p;
edge () {}
edge (int _x, int _y, int _c, int _p) : x(_x), y(_y), c(_c), p(_p) {}
bool operator<(const edge& e) const {
if (c != e.c) return c < e.c;
return p < e.p;
}
};
int N, M, D, P, cost, T[ NMAX ];
vector< edge > E, sol;
set<int> rez;
int djset(int x) {
if (T[ x ] != x) {
T[ x ] = djset( T[ x ] );
}
return T[ x ];
}
int reunion(int x, int y) {
T[ djset(x) ] = djset( y );
}
int main() {
freopen("politie.in", "r", stdin);
freopen("politie.out", "w", stdout);
scanf("%d%d%d%d", &N, &M, &D, &P);
while (M--) {
int x, y, c, p;
scanf("%d%d%d%d", &x, &y, &c, &p);
E.push_back( edge(x, y, c, p) );
}
sort(E.begin(), E.end());
for (int i = 1; i <= N; ++i) {
T[ i ] = i;
}
vector<edge>::iterator k;
for (vector<edge>::iterator it = E.begin(); it != E.end(); ++it) {
int x = it->x, y = it->y, c = it->c;
if (djset(x) != djset(y)) {
//printf("%d %d %d %d\n", x, y, c, it->p);
reunion(x, y);
cost += c;
sol.push_back( *it );
rez.insert( it->p );
if (sol.size() == N - 1) {
++it;
k = it;
break;
}
if (rez.size() == P) {
break;
}
}
}
for (vector<edge>::iterator it = E.begin(); it != k; ++it) {
rez.insert( it->p );
if (rez.size() == P) {
break;
}
}
while (rez.size() != P && k != E.end()) {
rez.insert( k->p );
if (rez.size() == P) {
break;
}
++k;
}
for (set<int>::reverse_iterator it = rez.rbegin(); it != rez.rend(); ++it) {
printf("%d\n", *it);
}
return 0;
}