#include <iostream>
#include <vector>
#include <tuple>
#include <algorithm>
using namespace std;
#pragma warning (disable : 4996)

class UnionFind {
public:
	vector<int> par;

	void init(int sz) {
		par.resize(sz, -1);
	}
	int root(int pos) {
		if (par[pos] == -1) return pos;
		par[pos] = root(par[pos]);
		return par[pos];
	}
	void unite(int u, int v) {
		u = root(u); v = root(v);
		if (u == v) return;

		par[u] = v;
	}
	bool same(int u, int v) {
		if (root(u) == root(v)) return true;
		return false;
	}
};

class MergeTech {
public:
	vector<int> group;
	vector<pair<long long, int>> maxv;
	vector<vector<int>> G;
	vector<long long> cost, BB;

	void init(vector<long long> B) {
		group.resize(B.size(), 0);
		maxv.resize(B.size(), make_pair(0, 0));
		G.resize(B.size(), vector<int>(0, 0));
		cost = B;
		BB = B;
		for (int i = 0; i < B.size(); i++) { group[i] = i; maxv[i] = make_pair(B[i], i); G[i].push_back(i); }
	}
	bool same(int u, int v) {
		if (group[u] == group[v]) return true;
		return false;
	}
	void unite(int u, int v) {
		u = group[u];
		v = group[v]; if (G[u].size() < G[v].size()) swap(u, v);

		for (int i = 0; i < G[v].size(); i++) {
			group[G[v][i]] = u;
			maxv[u] = max(maxv[u], make_pair(BB[G[v][i]], G[v][i]));
			G[u].push_back(G[v][i]);
		}
		G[v].clear();
		cost[u] += cost[v];
		cost[v] = 0;
	}
	long long getval(int pos) {
		pos = group[pos];
		return cost[pos];
	}
	long long getmax(int pos) {
		pos = group[pos];
		return maxv[pos].second;
	}
};

long long N, M, A[1 << 17], B[1 << 17], U[1 << 17], V[1 << 17];
long long Subtree[1 << 17];
vector<tuple<long long, int, int, int>> L;
vector<int> Y[1 << 17];
MergeTech UF1, UF2;

int dfs(int pos, long long rem) {
	if (A[pos] > rem - B[pos] || Subtree[pos] > rem) return 0;

	int ans = 0; if (Y[pos].size() == 0) ans = 1;
	for (int i = 0; i < Y[pos].size(); i++) {
		if (A[pos] > rem - Subtree[pos] + Subtree[Y[pos][i]]) continue;

		long long val = rem - Subtree[pos] + Subtree[Y[pos][i]];
		if (A[pos] <= rem - Subtree[pos]) val += B[pos];
		ans |= dfs(Y[pos][i], val);
	}
	return ans;
}

int main() {
	scanf("%lld%lld", &N, &M);
	for (int i = 0; i < N; i++) { scanf("%lld%lld", &A[i], &B[i]); A[i] -= B[i]; }
	for (int i = 0; i < M; i++) { scanf("%lld%lld", &U[i], &V[i]); U[i]--; V[i]--; }
	for (int i = 0; i < M; i++) L.push_back(make_tuple(max(A[U[i]], A[V[i]]), max(U[i], V[i]), U[i], V[i]));
	sort(L.begin(), L.end());
	vector<long long>AA(N, 0); for (int i = 0; i < N; i++) AA[i] = A[i];
	vector<long long>BB(N, 0); for (int i = 0; i < N; i++) BB[i] = B[i];

	UF1.init(AA); UF2.init(BB);
	for (int i = 0; i < L.size(); i++) {
		int r1 = get<2>(L[i]), r2 = get<3>(L[i]);
		if (UF1.same(r1, r2) == false) {
			if (make_pair(A[r1], r1) > make_pair(A[r2], r2)) {
				int t = UF1.getmax(r2);
				Y[r1].push_back(t);
			}
			else {
				int t = UF1.getmax(r1);
				Y[r2].push_back(t);
			}
			UF1.unite(get<2>(L[i]), get<3>(L[i]));
		}
	}

	vector<pair<long long, int>> I;
	for (int i = 0; i < N; i++) I.push_back(make_pair(A[i], i));
	sort(I.begin(), I.end());

	for (int i = 0; i < I.size(); i++) {
		for (int j : Y[I[i].second]) {
			UF2.unite(I[i].second, j);
		}
		Subtree[I[i].second] = UF2.getval(I[i].second);
	}

	dfs(I[I.size() - 1].second, 1000006200);

	long long cl = 0, cr = (1LL << 60), cm, minx = (1LL << 60);
	for (int i = 0; i < 70; i++) {
		cm = (cl + cr) / 2;
		int J = dfs(I[I.size() - 1].second, cm);
		if (J == 1) { minx = min(minx, cm); cr = cm; }
		else { cl = cm; }
	}
	cout << minx << endl;
	return 0;
}

Measured memory_bytes: 42224