Problem:
Score : 1000 points

Problem Statement

There is a simple undirected graph with N vertices and M edges.
The vertices are numbered 1 through N, and the edges are numbered 1 through M.
Edge i connects Vertex U_i and V_i.
Also, Vertex i has two predetermined integers A_i and B_i.
You will play the following game on this graph.

First, choose one vertex and stand on it, with W yen (the currency of Japan) in your pocket.
Here, A_s \leq W must hold, where s is the vertex you choose.
Then, perform the following two kinds of operations any number of times in any order:

Choose one vertex v that is directly connected by an edge to the vertex you are standing on, and move to vertex v. Here, you need to have at least A_v yen in your pocket when you perform this move.

Donate B_v yen to the vertex v you are standing on. Here, the amount of money in your pocket must not become less than 0 yen.

You win the game when you donate once to every vertex.
Find the smallest initial amount of money W that enables you to win the game.

Constraints

1 \leq N \leq 10^5

N-1 \leq M \leq 10^5

1 \leq A_i,B_i \leq 10^9

1 \leq U_i < V_i \leq N

The given graph is connected and simple (there is at most one edge between any pair of vertices).

Input

Input is given from Standard Input in the following format:

N M
A_1 B_1
A_2 B_2
:
A_N B_N
U_1 V_1
U_2 V_2
:
U_M V_M

Output

Print the smallest initial amount of money W that enables you to win the game.

Sample Input 1

4 5
3 1
1 2
4 1
6 2
1 2
2 3
2 4
1 4
3 4

Sample Output 1

6

If you have 6 yen initially, you can win the game as follows:

Stand on Vertex 4. This is possible since you have not less than 6 yen.

Donate 2 yen to Vertex 4. Now you have 4 yen.

Move to Vertex 3. This is possible since you have not less than 4 yen.

Donate 1 yen to Vertex 3. Now you have 3 yen.

Move to Vertex 2. This is possible since you have not less than 1 yen.

Move to Vertex 1. This is possible since you have not less than 3 yen.

Donate 1 yen to Vertex 1. Now you have 2 yen.

Move to Vertex 2. This is possible since you have not less than 1 yen.

Donate 2 yen to Vertex 2. Now you have 0 yen.

If you have less than 6 yen initially, you cannot win the game. Thus, the answer is 6.

Sample Input 2

5 8
6 4
15 13
15 19
15 1
20 7
1 3
1 4
1 5
2 3
2 4
2 5
3 5
4 5

Sample Output 2

44

Sample Input 3

9 10
131 2
98 79
242 32
231 38
382 82
224 22
140 88
209 70
164 64
6 8
1 6
1 4
1 3
4 7
4 9
3 7
3 9
5 9
2 5

Sample Output 3

582

Solution in Rust (1.15.1) (judge verdict: Runtime Error)

use std::io;
use std::io::BufRead;

fn main() {
    let mut sc = new(std::io::stdin());

    let n:usize = sc.next();
    let m:usize = sc.next();
    let mut node:Vec<(i32, i32)> = vec![];
    for _ in 0..n {
        node.push((sc.next(), sc.next())); // a, b
    }
    if n == 1 {
        let res = if node[0].0 > node[0].1 {
            node[0].0
        } else {
            node[0].1
        };
        println!("{}", res);
        return;
    }
    let mut edges:Vec<Vec<(i32, usize, usize)>> = vec![vec![]; n];
    for _ in 0..m {
        let mut from:usize = sc.next();
        let mut to: usize = sc.next();
        from = from.wrapping_sub(1);
        to = to.wrapping_sub(1);
        let w = node[to].0 - node[to].1;
        edges[from].push((-w, from, to));
        let w = node[from].0 - node[from].1;
        edges[to].push((-w, to, from));
    }
    for i in 0..n {
        edges[i].sort()
    }

    let mut left = -1;
    let mut right = 1_000_000_000;
    let mut queue = std::collections::BinaryHeap::new();
    while right - left > 1 {
        let have = (left + right) / 2;

        queue.clear();

        let mut uf = UnionFind::new(n);
        let mut rootw = vec![-1; n];
        for i in 0..n {
            if node[i].0 - node[i].1 <= have {
                for e in &edges[i] {
                    queue.push(e.clone());
                }
                rootw[i] = have + node[i].1;
            }
        }
        // println!("mid: {}", have);
        // println!("q: {:?}", queue);
        let mut used_edges = 0;
        loop {
            if let Some((w, from, to)) = queue.pop() {
                let w = -w;
                // println!("{:?}", (w, from, to));
                let cur = rootw[uf.root(from)];
                assert!(cur >= 0);
                if w <= cur && uf.root(from) != uf.root(to) {
                    used_edges += 1;
                    let add = if rootw[uf.root(to)] == -1 {
                        for e in &edges[to] {
                            queue.push(e.clone());
                        }
                        node[to].1
                    } else {
                        rootw[uf.root(to)] - have
                    };
                    assert!(add >= 0);
                    let nxt = cur + add;
                    uf.union(from, to);
                    rootw[uf.root(to)] = nxt;
                }
            } else {
                break;
            }
        }
        // println!("used: {}", used_edges);

        if used_edges >= n - 1 {
            assert_eq!(used_edges, n-1);
            right = have;
        } else {
            left = have;
        }
    }

    let mut res = right;
    for (_, b) in node {
        res += b;
    }
    println!("{}", res);
}


pub struct Scanner<R: io::Read> {
    br: io::BufReader<R>,
    // Read tokens are stored in reversed order per line.
    buf: Vec<String>,
}

pub fn new<R: io::Read>(r: R) -> Scanner<R> {
    Scanner::new(r)
}

impl<R: io::Read> Scanner<R> {
    #[inline]
    fn new(r: R) -> Scanner<R> {
        Scanner {
            br: io::BufReader::new(r),
            buf: vec![],
        }
    }
    #[inline]
    pub fn next<T>(&mut self) -> T
        where T: std::str::FromStr,
              T::Err: std::fmt::Debug
    {
        self.next_string().map(|s| s.parse::<T>().expect("Parse failed: ")).unwrap()
    }
    fn next_string(&mut self) -> Option<String> {
        self.buf.pop().or_else(|| match self.update() {
            true => self.next_string(),
            false => None,
        })
    }
    #[inline]
    fn update(&mut self) -> bool {
        let mut s = String::new();
        let res = self.br.read_line(&mut s);
        match res.expect("I/O error.") {
            0 => false,
            _ => {
                self.buf = s.split_whitespace().map(|x| x.to_string()).rev().collect();
                true
            }
        }
    }
}

pub struct UnionFind {
    tree: Vec<isize>,
}

impl UnionFind {
    /// Creates n disjoint singleton sets.
    #[inline]
    pub fn new(n: usize) -> UnionFind {
        UnionFind { tree: vec![-1; n] }
    }
    /// Returns the root of the tree containing i.
    pub fn root(&mut self, i: usize) -> usize {
        if self.tree[i] < 0 {
            return i;
        }
        let j = self.tree[i];
        let root = self.root(j as usize);
        // Path decomposition.
        self.tree[i] = root as isize;
        root
    }
    /// Returns the size of the tree containing i.
    #[inline]
    pub fn size(&mut self, i: usize) -> usize {
        let root = self.root(i);
        -self.tree[root] as usize
    }
    /// Unions i and j.
    pub fn union(&mut self, i: usize, j: usize) {
        let mut i = self.root(i);
        let mut j = self.root(j);
        if i == j {
            return;
        }
        if -self.tree[i] > -self.tree[j] {
            let tmp = i;
            i = j;
            j = tmp;
        }
        // Append i to j since size(i) <= size(j).
        self.tree[j] += self.tree[i];
        self.tree[i] = j as isize;
    }
}