#include <bits/stdc++.h>
using namespace std;
using vec = vector<long long>;
using mat = vector<vec>;
using Pii = pair<long long, long long>;
using PiP = pair<long long, Pii>;
using PPi = pair<Pii, long long>;
using bools = vector<bool>;
template <typename T>
void readv(vector<T> &a) {
  for (long long i = (0); i < (a.size()); i++) cin >> a[i];
}
void readi(vector<long long> &a) {
  for (long long i = (0); i < (a.size()); i++) {
    cin >> a[i];
    a[i]--;
  }
}
template <typename T>
void debug(vector<vector<T>> m) {
  for (long long i = (0); i < (m.size()); i++) {
    for (long long j = (0); j < (m[i].size()); j++) {
      cout << m[i][j] << ",";
    }
    cout << endl;
  }
}
void unite_que(priority_queue<Pii, vector<Pii>, greater<Pii>> &q1,
               priority_queue<Pii, vector<Pii>, greater<Pii>> &q2) {
  if (q2.size() > q1.size()) q1.swap(q2);
  while (!q2.empty()) {
    q1.push(q2.top());
    q2.pop();
  }
}
class Union_find {
 public:
  vector<long long> par;
  vector<long long> sz, dat;
  vector<priority_queue<Pii, vector<Pii>, greater<Pii>>> que;
  Union_find(long long N, vector<long long> v) {
    par = vector<long long>(N);
    for (long long i = (0); i < (N); i++) par[i] = i;
    sz = vector<long long>(N, 1);
    dat = v;
  }
  long long find(long long x) {
    if (par[x] == x)
      return x;
    else
      return par[x] = find(par[x]);
  }
  void unite(long long x, long long y) {
    x = find(x);
    y = find(y);
    if (x == y) return;
    if (sz[x] < sz[y]) swap(x, y);
    par[y] = x;
    sz[x] += sz[y];
    dat[x] += dat[y];
    unite_que(que[x], que[y]);
  }
  bool is_union(long long x, long long y) {
    x = find(x);
    y = find(y);
    return x == y;
  }
  long long union_size(long long x) { return sz[find(x)]; }
};
struct edge {
  long long to, cost;
};
class Graph {
 public:
  long long V;
  vector<vector<edge>> G;
  Graph(long long V) : V(V) { G = vector<vector<edge>>(V, vector<edge>(0)); }
  void add_edge(long long from, long long to, long long cost) {
    G[from].push_back(edge({to, cost}));
  }
  void add_edge2(long long v1, long long v2, long long cost) {
    add_edge(v1, v2, cost);
    add_edge(v2, v1, cost);
  }
  void dfs(long long v, long long w, Union_find &UF) {
    if (UF.union_size(v) > 1) return;
    while (!UF.que[UF.find(v)].empty()) {
      long long par = UF.find(v);
      Pii p = UF.que[par].top();
      if (p.first > UF.dat[par] + w) break;
      UF.que[par].pop();
      UF.unite(par, p.second);
    }
  }
};
void init(Graph &G, Union_find &UF, vec &A, long long N) {
  UF.que = vector<priority_queue<Pii, vector<Pii>, greater<Pii>>>(N);
  for (long long i = (0); i < (N); i++)
    for (long long k = (0); k < (G.G[i].size()); k++)
      UF.que[i].push(Pii(A[G.G[i][k].to], G.G[i][k].to));
}
signed main() {
  long long N, M;
  cin >> N >> M;
  Graph G(N);
  vec A(N), B(N);
  long long S = 0;
  for (long long i = (0); i < (N); i++) {
    cin >> A[i] >> B[i];
    S += B[i];
    A[i] -= B[i];
  }
  long long U, V;
  for (long long i = (0); i < (M); i++) {
    cin >> U >> V;
    G.add_edge2(U - 1, V - 1, 0);
  }
  if (N == 1) {
    cout << max(A[0] + B[0], B[0]) << endl;
    return 0;
  }
  long long w1 = -1, w2 = 1000000000;
  while (w2 - w1 > 1) {
    long long w = (w1 + w2 + 1) / 2;
    Union_find UF(N, B);
    init(G, UF, A, N);
    for (long long i = (0); i < (N); i++)
      if (w >= A[i]) G.dfs(i, w, UF);
    if (UF.union_size(0) == N)
      w2 = w;
    else
      w1 = w;
  }
  cout << w2 + S << endl;
  return 0;
}
