#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <queue>
#include <tuple>
#include <vector>
#define rep(i, n) for (int i = 0; i < (n); i++)
using namespace std;

double f(double w, double t, double c, double d) {
  return t + w + c + (d / (t + w + 1.0));
}

int64_t get_wait(int64_t time, int64_t c, int64_t d) {
  double low = 0;
  double high = 1e9;
  int cnt = 64;
  while (cnt--) {
    double c1 = (low * 2 + high) / 3;
    double c2 = (low + high * 2) / 3;
    if (f(c1, time, c, d) > f(c2, time, c, d))
      low = c1;
    else
      high = c2;
  }
  return ceil(low);
}

int main(void) {
  ios::sync_with_stdio(false);
  int N, M;
  cin >> N >> M;
  using gtype = tuple<int64_t, int64_t, int64_t>;
  vector<vector<gtype>> G(N);
  rep(i, M) {
    int A, B;
    int64_t C, D;
    cin >> A >> B >> C >> D;
    A--, B--;
    G[A].emplace_back(B, C, D);
    G[B].emplace_back(A, C, D);
  }

  using qtype = tuple<int64_t, int64_t>;
  priority_queue<qtype, vector<qtype>, greater<qtype>> que;
  que.emplace(0, 0);
  vector<int64_t> visit(N, INT64_MAX / 2);
  visit[0] = 0;
  while (!que.empty()) {
    auto [time, u] = que.top();
    que.pop();
    if (u == N - 1) {
      cout << time << endl;
      return 0;
    }
    if (visit[u] < time) continue;

    for (const auto& [v, c, d] : G[u]) {
      int64_t wait = get_wait(time, c, d);
      int64_t ntime = time + wait + c + d / (time + wait + 1);
      if (ntime < visit[v]) {
        visit[v] = ntime;
        que.emplace(ntime, v);
      }
    }
  }
  cout << -1 << endl;
  return 0;
}

#include <bits/stdc++.h>
#define rep(i, n) for(int i= 0; i < (n); i++)
using ll= long long int;
using namespace std;
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
ll mod= 1e9 + 7;


struct UnionFind {
    //自身が親であれば、その集合に属する頂点数に-1を掛けたもの
    //そうでなければ親のid
    vector<int> r;
 
    UnionFind(int N) {
        r = vector<int>(N, -1);
    }
 
    int root(int x) {
        if (r[x] < 0) return x;
        return r[x] = root(r[x]);
    }
 
    bool unite(int x, int y) {
        x = root(x);
        y = root(y);
        if (x == y) return false;
        if (r[x] > r[y]) swap(x, y);
        r[x] += r[y];
        r[y] = x;
        return true;
    }
 
    int size(int x) {
        return -r[root(x)];
    }
};


int main() {
  int n,m;
  cin >> n >> m;
  ll a[n],b[n];
  rep(i,n)cin >> a[i];
  rep(i,n)cin >> b[i];

  UnionFind tree(n);
  rep(i,m){
    int a,b;
    cin >> a >> b;
    a--,b--;
    tree.unite(a,b);
  }

  ll ansa[n]={},ansb[n]={};
  rep(i,n){
    ll ak=a[i],bk=b[i];
    a[i]=0,b[i]=0;
    ansa[tree.root(i)]+=ak;
    ansb[tree.root(i)]+=bk;
  }
  //rep(i,n)cout << ansa[i] << " " << ansb[i] << " " << tree.root(i) << endl;
  rep(i,n)if(ansa[tree.root(i)]!=ansb[tree.root(i)]){cout << "No" << endl; return 0;}
  cout << "Yes" << endl;

}