#include <bits/stdc++.h>
using namespace std;
ifstream in("politie.in");
ofstream out("politie.out");
const int N_MAX = 250000, M_MAX = 500000;
struct Edge
{
int x, y, c, gr;
bool operator <(const Edge& other) const
{
if(c == other.c)
return gr < other.gr;
return c < other.c;
}
};
int n, m, d, p;
Edge edges[M_MAX + 2];
set<int> tmp;
vector<int> ans;
int daddy[N_MAX + 2], depth[N_MAX + 2];
int root(int node)
{
int ans = daddy[node];
while(daddy[ans] != ans)
ans = daddy[ans];
return ans;
}
void join(int rootX, int rootY)
{
if(depth[rootX] == depth[rootY])
{
daddy[rootY] = rootX;
depth[rootX]++;
}
else if(depth[rootX] < depth[rootY])
daddy[rootX] = rootY;
else
daddy[rootY] = rootX;
}
int main()
{
in >> n >> m >> d >> p;
for(int i = 1; i <= m; i++)
in >> edges[i].x >> edges[i].y >> edges[i].c >> edges[i].gr;
sort(edges + 1, edges + m + 1);
for(int i = 1; i <= n; i++)
{
daddy[i] = i;
depth[i] = 1;
}
for(int i = 1; i <= m; i++)
{
int rootX = root(edges[i].x), rootY = root(edges[i].y);
if(rootX != rootY)
{
tmp.insert(edges[i].gr);
join(rootX, rootY);
}
}
for(auto it: tmp)
ans.push_back(it);
for(int i = ans.size() - 1; i >= ans.size() - p && i >= 0; i--)
out << ans[i] << '\n';
return 0;
}