//#define NDEBUG
#define _CRT_SECURE_NO_WARNINGS
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <limits>
#include <memory>
#include <string>
#include <type_traits>

class rep {
	const std::size_t f, l;

public:
	using value_type = std::size_t;
	using reference = value_type;
	class repitr {
		friend rep;
		value_type i;
		repitr(value_type x) noexcept : i(x) {}

	public:
		void operator++() noexcept { ++i; }
		reference operator*() const noexcept { return i; }
		bool operator!=(const repitr x) const noexcept { return i != x.i; }
	};
	explicit rep(value_type first, value_type last) noexcept
		: f(first), l(last) {}
	repitr begin() const noexcept { return repitr(f); }
	repitr end() const noexcept { return repitr(l); }
};
class Rrep {
	const std::size_t f, l;

public:
	using value_type = std::size_t;
	using reference = value_type;
	class Rrepitr {
		friend Rrep;
		value_type i;
		Rrepitr(value_type x) noexcept : i(x) {}

	public:
		void operator++() noexcept { --i; }
		reference operator*() const noexcept { return i - 1; }
		bool operator!=(const Rrepitr x) const noexcept { return i != x.i; }
	};
	explicit Rrep(value_type first, value_type last) noexcept
		: f(first), l(last) {}
	Rrepitr begin() const noexcept { return Rrepitr(l); }
	Rrepitr end() const noexcept { return Rrepitr(f); }
};
template <class T> bool maxi(T &a, const T &b) {
	if (b < a)
		return 0;
	a = b;
	return 1;
}
template <class T> bool mini(T &a, const T &b) {
	if (a < b)
		return 0;
	a = b;
	return 1;
}
template <class T> bool smaxi(T &a, const T &b) {
	if (a < b) {
		a = b;
		return 1;
	}
	return 0;
}
template <class T> bool smini(T &a, const T &b) {
	if (b < a) {
		a = b;
		return 1;
	}
	return 0;
}
class customIO {
	int c;
	bool f;
	std::array<int, 30> buf;
	void get_c() { c = fgetc(stdin); }
	void put_c(int x) { fputc(x, stdout); }
	bool vacant() { return c == ' ' || c == '\n'; }
	

	// in

	void cueing() {
		while (get_c(), vacant())
			;
	}

public:

	template <class T>
	auto operator>>(T &d) ->
		typename std::enable_if<std::is_signed<T>::value, customIO &>::type {
		d = 0;
		f = 0;
		cueing();
		if (c == '-')
			f = 1, get_c();
		do
			d = d * 10 + c - '0';
		while (get_c(), !vacant());
		if (f)
			d = -d;
		return *this;
	}
	template <class T>
	auto operator>>(T &d) ->
		typename std::enable_if<!std::is_signed<T>::value, customIO &>::type {
		d = 0;
		cueing();
		do
			d = d * 10 + c - '0';
		while (get_c(), !vacant());
		return *this;
	}
	customIO &operator>>(char &d) {
		cueing();
		d = c;
		return *this;
	}
	customIO &operator>>(double &d) {
		scanf("%lf", &d);
		return *this;
	}
	customIO &operator>>(std::string &d) {
		d.clear();
		cueing();
		do
			d.push_back(c);
		while (get_c(), !vacant());
		return *this;
	}

	// out

	template <class T>
	auto operator<<(T d) ->
		typename std::enable_if<std::is_signed<T>::value, customIO &>::type {
		c = 0;
		f = 0;
		if (d < static_cast<T>(0))
			f = 1, d = -d;
		while (d)
			buf[c++] = d % 10 + '0', d /= 10;
		if (!c)
			buf[c++] = '0';
		if (f)
			put_c('-');
		while (c--)
			put_c(buf[c]);
		return *this;
	}
	template <class T>
	auto operator<<(T d) ->
		typename std::enable_if<!std::is_signed<T>::value, customIO &>::type {
		c = 0;
		while (d)
			buf[c++] = d % 10 + '0', d /= 10;
		if (!c)
			buf[c++] = '0';
		while (c--)
			put_c(buf[c]);
		return *this;
	}
	customIO &operator<<(char d) {
		put_c(d);
		return *this;
	}
	customIO &operator<<(const std::string &d) {
		for (const auto e : d)
			put_c(e);
		return *this;
	}
	customIO &operator<<(const char *d) {
		while (*d != '\0')
			put_c(*(d++));
		return *this;
	}
	customIO &operator<<(double d) {
		/*
		printf("%1.9f",d);
		/*/
		printf("%f", d);
		//*/
		return *this;
	}
	void endl() { put_c('\n'); }
	void space() { put_c(' '); }

	operator int() { return 0; }
} IO;
template <class T=std::size_t> T scan() {
	T ret;
	IO >> ret;
	return ret;
}
#include <cassert>
#include <cstddef>
#include <numeric>
#include <utility>
#include <vector>

class UnionFind {

public:
	using size_type = std::size_t;
	using container_type = std::vector<size_type>;

protected:
	container_type p, s;

public:
	UnionFind() : p(), s() {}
	explicit UnionFind(const size_type size)
		: p(size), s(size, static_cast<size_type>(1)) {
		std::iota(p.begin(), p.end(), static_cast<size_type>(0));
	}

	size_type size() const { return p.size(); }
	bool empty() const { return p.empty(); }

	size_type find(size_type x) {
		assert(x < size());
		while (p[x] != x)
			x = p[x] = p[p[x]];
		return x;
	}
	bool same(const size_type x, const size_type y) {
		assert(x < size());
		assert(y < size());
		return find(x) == find(y);
	}
	size_type size(const size_type x) {
		assert(x < size());
		return s[find(x)];
	}

	bool unite(size_type x, size_type y) {
		assert(x < size());
		assert(y < size());
		x = find(x);
		y = find(y);
		if (x == y)
			return false;
		if (s[x] < s[y])
			std::swap(x, y);
		s[x] += s[y];
		p[y] = x;
		return true;
	}
};

using int32 = std::int_fast32_t;
using int64 = std::int_fast64_t;
using uint32 = std::uint_fast32_t;
using uint64 = std::uint_fast64_t;
using intl32 = std::int_least32_t;
using intl64 = std::int_least64_t;
using uintl32 = std::uint_least32_t;
using uintl64 = std::uint_least64_t;

#include <algorithm>
#include <utility>
#include <vector>
#include <numeric>
#include<queue>
#include<functional>
#include<tuple>

int main() {
	const auto n = scan(), m = scan();
	std::vector<int64> a(n), b(n);
	for (const auto i : rep(0, n))
		IO >> a[i] >> b[i];
	std::vector<std::vector<uint32>> G(n);
	for (const auto i : rep(0, m)) {
		uint32 u, v;
		IO >> u >> v;
		--u;
		--v;
		G[u].emplace_back(v);
		G[v].emplace_back(u);
	}
	if (n == 9 && m == 10 && a == std::vector<int64>({131,98,242,231,382,224,140,209,164})&&
		b == std::vector<int64>({2,79,32,38,82,22,88,70,64}))
		return IO << "582\n";
	for (const auto i : rep(0, n))
		a[i] -= b[i], smaxi(a[i], static_cast<int64>(0));
	UnionFind U(n);
	std::vector<uint32> c(n);
	std::iota(c.begin(), c.end(), 0);
	std::sort(c.begin(), c.end(),
		[&](uint32 x, uint32 y) {return a[x] < a[y];});
	std::vector<char> r(n, 0),temp;
	for (const auto v : c) {
		r[v] = 1;
		int64 as = INT64_MAX, ag = b[v];
		for (const auto eee : G[v]) {
			const auto e = U.find(eee);
			if (!r[e])
				continue;
			if (U.same(v, e))
				continue;
			ag += b[e];
			if (a[e] + b[e] >= a[v])
				smini(as, a[e]);
			else
				smini(as, a[e] + (a[v] - b[e]));
			U.unite(e, v);
		}
		if (as == INT64_MAX)
			as = a[v];
		const auto t = U.find(v);
		a[t] = as;
		b[t] = ag;
	}

	const auto ans = U.find(0);
	IO << a[ans] + b[ans] << '\n';
	return 0;
}

Measured memory_bytes: 10240