#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; struct UnionFind { vector par; vector size; UnionFind() {} UnionFind(int n) { par.resize(n); size.resize(n,1); for(int i = 0; i < n; i++) { par[i] = i; } } int find(int x) { if(par[x] == x) { return x; } return par[x] = find(par[x]); } bool same(int x, int y) { return find(x) == find(y); } int consize(int x) { return size[find(x)]; } bool unite(int x, int y) { x = find(x); y = find(y); if(x == y) { return false; } if(size[x] > size[y]) { swap(x,y); } par[x] = y; size[y] += size[x]; return true; } }; int inf = 1001001001; template struct SegmentTree { int n; vector dat; SegmentTree() {} SegmentTree(int N) { n = 1; while(n < N) { n *= 2; } dat.resize(2*n-1,-inf); } void update(int x, T val) { x += n-1; dat[x] = val; while(x > 0) { x = (x-1)/2; dat[x] = max(dat[2*x+1],dat[2*x+2]); } } T query(int a, int b, int k, int l, int r) { if(r <= a || b <= l) return -inf; if(a <= l && r <= b) return dat[k]; T vl = query(a, b, 2*k+1, l, (l+r)/2); T vr = query(a, b, 2*k+2, (l+r)/2, r); return max(vl, vr); } T query(int a,int b) {//[a,b) return query(a,b,0,0,n); } }; struct HLD { // 根が 0 でない時に注意 vectorp,sz,in,nxt; SegmentTree seg; void dfs1(vector>&c,int v = 0) { sz[v] = 1; for(int &w:c[v]) { dfs1(c,w); sz[v] += sz[w]; if(sz[w] > sz[c[v][0]]) { swap(w,c[v][0]); } } } void dfs2(vector>&c,int &t,int v = 0) { in[v] = t; t++; for(int w:c[v]) { if(w == c[v][0]) { nxt[w] = nxt[v]; } else { nxt[w] = w; } dfs2(c,t,w); } } HLD(vector&A,vector&p,vector>&c):p(p) { int N = A.size(); sz.resize(N,0); dfs1(c); in.resize(N,0); nxt.resize(N,0); int t = 0; dfs2(c,t); vectortmp(N); for(int i = 0; i < N; i++) { tmp[in[i]] = A[i]; } SegmentTreeinit(tmp.size()); for(int i = 1; i < tmp.size(); i++) { init.update(i,tmp[i]); } seg = init; } int lca(int u,int v) { while(true) { if(in[u] > in[v]) { swap(u,v); } if(nxt[u] == nxt[v]) { return u; } v = p[nxt[v]]; } } int query(int u,int v) { int w = lca(u,v); int ans = 0; while(nxt[u] != nxt[w]) { ans = max(ans,seg.query(in[nxt[u]],in[u]+1)); u = p[nxt[u]]; } ans = max(ans,seg.query(in[w]+1,in[u]+1)); while(nxt[v] != nxt[w]) { ans = max(ans,seg.query(in[nxt[v]],in[v]+1)); v = p[nxt[v]]; } ans = max(ans,seg.query(in[w]+1,in[v]+1)); return ans; } }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N,K; long long C; cin >> N >> K >> C; vectoru(K),v(K),w(K),p(K); vector>tmp; for(int i = 0; i < K; i++) { cin >> u[i] >> v[i] >> w[i] >> p[i]; u[i]--; v[i]--; tmp.push_back({w[i],u[i],v[i]}); } sort(tmp.begin(),tmp.end()); vector>>ki(N); UnionFind uf(N); long long cost = 0; for(int i = 0; i < K; i++) { if(uf.unite(tmp[i][1],tmp[i][2])) { cost += tmp[i][0]; ki[tmp[i][1]].push_back({tmp[i][2],tmp[i][0]}); ki[tmp[i][2]].push_back({tmp[i][1],tmp[i][0]}); } } if(cost > C) { cout << -1 << "\n"; return 0; } vectorP(N,-1); vectora(N,-1); vector>c(N); queueque; que.push(0); while(!que.empty()) { int x = que.front(); que.pop(); for(auto i:ki[x]) { if(i.first != 0 && P[i.first] == -1) { P[i.first] = x; c[x].push_back(i.first); a[i.first] = i.second; que.push(i.first); } } } HLD hld(a,P,c); int ans = 0; for(int i = 0; i < K; i++) { int mx = hld.query(u[i],v[i]); if(cost-mx+w[i] <= C) { ans = max(ans,p[i]); } } cout << ans << "\n"; }