#include using namespace std; #define rep(i, n) for (int i = 0; i < (int)(n); i++) #define length size() #define int long long #define ll long long constexpr ll inf = 1001001001001001001ll; constexpr ll mod = 1000000007; constexpr double pi = 3.141592653589793; //小数出力 //cout << std::setprecision(12); //imos void to_ruiseki(vector &vec){ for(int i=1;i> &vec){ rep(i,vec.size()){ rep(j,vec[0].size()){ int s = 0; if(i!=0) s += vec[i-1][j]; if(j!=0) s += vec[i][j-1]; if(i!=0 && j!=0) s -= vec[i-1][j-1]; s += vec[i][j]; vec[i][j] = s; } } } //modpow(a,n,mod) int modpow(int a, int n, int mod) { long long res = 1; while (n > 0) { if (n & 1) res = res * a % mod; a = a * a % mod; n >>= 1; } return res; } //素因数分解 vector> p_fact(int N) { vector> res; for (int a = 2; a * a <= N; ++a) { if (N % a != 0) continue; int ex = 0; // 指数 // 割れる限り割り続ける while (N % a == 0) { ++ex; N /= a; } // その結果を push res.push_back({a, ex}); } // 最後に残った数について if (N != 1) res.push_back({N, 1}); return res; } //ctoi int ctoi(const char c){ switch(c){ case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; default : throw runtime_error("hoge"); } } //max template< typename T1, typename T2 > inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); } //min template< typename T1, typename T2 > inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); } //print void print() { cout << '\n'; } template void print(const T &t) { cout << t << '\n'; } template void print(const Head &head, const Tail &... tail) { cout << head << ' '; print(tail...); } //join template string join(vector &vec ,const string &sp){ int si = vec.length; if(si==0){ return ""; }else{ stringstream ss; rep(i,si-1){ ss << vec[i] << sp; } ss << vec[si - 1]; return ss.str(); } } //木の直径 int tree_diameter(vector> &vec){ //0-indexed queue> que; vector is_searched(vec.size(),false); que.push(make_pair(0,0)); int max_d = 0; int max_e = 0; while(!que.empty()){ int e = que.front().first; int distance = que.front().second; is_searched[e] = true; if(max_d> &vec,int st){ queue> que; vector is_searched(vec.size(),false); is_searched[st] = true; que.push(make_pair(st,0)); int max_d = 0; int max_e = 0; while(!que.empty()){ int e = que.front().first; int distance = que.front().second; if(max_d par, rank, siz; // 構造体の初期化 UnionFind(int n) : par(n,-1), rank(n,0), siz(n,1) { } // 根を求める int root(int x) { if (par[x]==-1) return x; // x が根の場合は x を返す else return par[x] = root(par[x]); // 経路圧縮 } // x と y が同じグループに属するか (= 根が一致するか) bool issame(int x, int y) { return root(x)==root(y); } // x を含むグループと y を含むグループを併合する bool unite(int x, int y) { int rx = root(x), ry = root(y); // x 側と y 側の根を取得する if (rx==ry) return false; // すでに同じグループのときは何もしない // union by rank if (rank[rx]0){ if(!is_searched_now[x-1][y] && vec[x-1][y] != '#'){ saiki(x-1,y,s+1); } if(vec[x-1][y] == 'g' && s >=2) chmax(max_ans,s+1); } if(x=2) chmax(max_ans,s+1); } if(y>0){ if(!is_searched_now[x][y-1] && vec[x][y-1] != '#'){ saiki(x,y-1,s+1); } if(vec[x][y-1] == 'g' && s >=2) chmax(max_ans,s+1); } if(y=2) chmax(max_ans,s+1); } //is_searched[x][y] = true; is_searched_now[x][y] = false; } int n,m,x; vector>> tree; bool solve(int width){ //print("solve:",width); priority_queue,vector>,greater>> que; vector is_checked(n,false); que.push(make_pair(0,0)); while(!que.empty()){ int t = que.top().first; int e = que.top().second; que.pop(); if(is_checked[e]) continue; is_checked[e] = true; if(e == n-1){ // print(width,"true"); return true; } //print(t,e); rep(i,tree[e].size()){ int ln = get<0>(tree[e][i]); int lt = get<1>(tree[e][i]); int lw = get<2>(tree[e][i]); if(lw < width) continue; if(t + lt > x) continue; // print("push:",t+lt,ln); que.push(make_pair(t + lt,ln)); } } // print(width,"false"); return false; } signed main(void){ cin >> n >> m >> x; tree.resize(n); rep(i,m){ int u1,u2,a,b; cin >> u1 >> u2 >> a >> b; u1--; u2--; tree[u1].push_back(make_tuple(u2,a,b)); tree[u2].push_back(make_tuple(u1,a,b)); } //めぐる式(https://qiita.com/drken/items/97e37dd6143e33a64c8c) int left = -1; //「index = 0」が条件を満たすこともあるので、初期値は -1 int right = powl(10,9)+1; // 「index = a.size()-1」が条件を満たさないこともあるので、初期値は a.size() /* どんな二分探索でもここの書き方を変えずにできる! */ while (right - left > 1) { int mid = left + (right - left) / 2; // print("bs:",left,right,mid); if (solve(mid)) left = mid; else right = mid; } /* left は条件を満たさない最大の値、right は条件を満たす最小の値になっている */ print(left); }