#include #include using namespace std; using namespace atcoder; #define rep(i, n) for(int i=0;i<(n);++i) #define rep1(i, n) for(int i=1;i<=(n);i++) #define ll long long using mint = modint998244353; using P = pair; using lb = long double; using T = tuple; #ifdef LOCAL # include # define dbg(...) debug_print::multi_print(#__VA_ARGS__, __VA_ARGS__) #else # define dbg(...) (static_cast(0)) #endif template inline bool chmax(T &a, T b) { return ((a < b) ? (a = b, true) : (false)); } // 辺に情報があるときlcaをみて子に持たせる。 class Node { public: int depth, parent, top, idxf, idxb; Node() : parent(-1) {} }; template class HLD { public: HLD() : HLD(vector>(0), -1) {} explicit HLD(vector> &tree, int root_) : HLD(tree, root_, vector(int(tree.size()), e())) {} explicit HLD(vector> &tree, int root_, const vector &v) : n(int(tree.size())), root(root_) { build_(tree, v); } void build(vector> &tree, int root_) { n = int(tree.size()); build(tree, root_, vector(n, e())); } void build(vector> &tree, int root_, const vector &v) { n = int(tree.size()); root = root_; build_(tree, v); } // set element to node void set(int node, S x) { stf.set(nodes[node].idxf, x); stb.set(nodes[node].idxb, x); } // lca int lca(int ln, int rn) { while (1) { int topl = nodes[ln].top, topr = nodes[rn].top; if (topl == topr) { if (nodes[ln].depth < nodes[rn].depth) return ln; else return rn; } if (nodes[topl].depth > nodes[topr].depth) ln = nodes[topl].parent; else rn = nodes[topr].parent; } } // path query S edge_query(int ln, int rn) { S prodl = e(), prodr = e(); while (1) { int topl = nodes[ln].top, topr = nodes[rn].top; if (topl == topr) { //子に情報があるから調整している if (nodes[ln].depth < nodes[rn].depth) { // rn is deeper than ln prodl = op(prodl, stf.prod(nodes[ln].idxf+1, nodes[rn].idxf+1)); } else { // ln is deeper than rn prodl = op(prodl, stb.prod(nodes[ln].idxb, nodes[rn].idxb)); } return op(prodl, prodr); } if (nodes[topl].depth > nodes[topr].depth) { prodl = op(prodl, stb.prod(nodes[ln].idxb, nodes[topl].idxb+1)); ln = nodes[topl].parent; } else { prodr = op(stf.prod(nodes[topr].idxf, nodes[rn].idxf+1), prodr); rn = nodes[topr].parent; } } } S vertex_query(int ln, int rn) { S prodl = e(), prodr = e(); while (1) { int topl = nodes[ln].top, topr = nodes[rn].top; if (topl == topr) { if (nodes[ln].depth < nodes[rn].depth) { // rn is deeper than ln prodl = op(prodl, stf.prod(nodes[ln].idxf, nodes[rn].idxf+1)); } else { // ln is deeper than rn prodl = op(prodl, stb.prod(nodes[ln].idxb, nodes[rn].idxb+1)); } return op(prodl, prodr); } if (nodes[topl].depth > nodes[topr].depth) { prodl = op(prodl, stb.prod(nodes[ln].idxb, nodes[topl].idxb+1)); ln = nodes[topl].parent; } else { prodr = op(stf.prod(nodes[topr].idxf, nodes[rn].idxf+1), prodr); rn = nodes[topr].parent; } } } private: int n, root; segtree stf, stb; vector nodes; void build_(vector> &tree, const vector &v) { assert(n == int(v.size())); assert(root < n); // create segtree stf = segtree(n); stb = segtree(n); nodes = vector(n); vector heavy(n, -1); pp1(tree, heavy, root, root, 0); pp2(tree, v, heavy, 0, root, root, root); } // set heavy node, parent, depth int pp1(vector> &tree, vector &heavy, int node, int p, int d) { nodes[node].parent = p; nodes[node].depth = d; int sz = 1, sz_max = 0, sz_c; for (int &c: tree[node]) { if (c == p) continue; sz_c = pp1(tree, heavy, c, node, d+1); // get child's size sz += sz_c; // update size if (chmax(sz_max, sz_c)) heavy[node] = c; // update heavy node } return sz; } // build segtree, set top int pp2(vector> &tree, const vector &v, vector &heavy, int tour_idx, int node, int p, int t) { nodes[node].idxf = tour_idx; stf.set(tour_idx++, v[node]); nodes[node].idxb = n - tour_idx; stb.set(n - tour_idx, v[node]); nodes[node].top = t; // set top if (heavy[node] >= 0) { // heavy node and depth first search tour_idx = pp2(tree, v, heavy, tour_idx, heavy[node], node, t); } for (int &c: tree[node]) { if (c == p || c == heavy[node]) continue; tour_idx = pp2(tree, v, heavy, tour_idx, c, node, c); // next node is top } return tour_idx; } }; int op(int a, int b) { return max(a,b); } int e(){ return 0; } int main() { int n, k; ll c; cin >> n >> k >> c; vector> g(n); vector u(k), v(k), w(k), p(k); rep(i,k){ cin >> u[i] >> v[i] >> w[i] >> p[i]; --u[i];--v[i]; } vector idx(k); rep(i,k) idx[i] = i; sort(idx.begin(),idx.end(),[&](int l, int r) { return w[l] used(k); rep(i,k) { int id = idx[i]; if(uf.same(u[id], v[id])) continue; else{ cost += w[id]; P = max(p[id],P); g[u[id]].push_back(v[id]); g[v[id]].push_back(u[id]); used[id] = true; uf.merge(u[id], v[id]); } } if(cost>c) { cout << -1 << endl; return 0; } int ans = P; HLD hld(g,0); rep(i,k){ if(used[i]) { dbg(u[i], v[i], hld.lca(u[i],v[i])); hld.set(u[i]+v[i]-hld.lca(u[i], v[i]), w[i]); } } dbg(ans); rep(i,k) { if(used[i]) continue; int mx = hld.edge_query(u[i], v[i]); ll ncost = cost - mx + w[i]; dbg(u[i], v[i]); if(ncost<=c) { ans = max(ans, p[i]); } } cout << ans << endl; }