pub trait IterScan: Sized {
    type Output;
    fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output>;
}
pub trait MarkedIterScan: Sized {
    type Output;
    fn mscan<'a, I: Iterator<Item = &'a str>>(self, iter: &mut I) -> Option<Self::Output>;
}
#[derive(Debug)]
pub struct Scanner<'a> {
    iter: std::str::SplitAsciiWhitespace<'a>,
}
impl<'a> Scanner<'a> {
    #[inline]
    pub fn new(s: &'a str) -> Self {
        let iter = s.split_ascii_whitespace();
        Self { iter }
    }
    #[inline]
    pub fn scan<T: IterScan>(&mut self) -> <T as IterScan>::Output {
        T::scan(&mut self.iter).unwrap()
    }
    #[inline]
    pub fn mscan<T: MarkedIterScan>(&mut self, marker: T) -> <T as MarkedIterScan>::Output {
        marker.mscan(&mut self.iter).unwrap()
    }
    #[inline]
    pub fn scan_vec<T: IterScan>(&mut self, size: usize) -> Vec<<T as IterScan>::Output> {
        (0..size)
            .map(|_| T::scan(&mut self.iter).unwrap())
            .collect()
    }
    #[inline]
    pub fn scan_chars(&mut self) -> Vec<char> {
        self.iter.next().unwrap().chars().collect::<Vec<char>>()
    }
    #[inline]
    pub fn scan_chars_with(&mut self, base: char) -> Vec<usize> {
        self.iter
            .next()
            .unwrap()
            .chars()
            .map(|c| (c as u8 - base as u8) as usize)
            .collect::<Vec<usize>>()
    }
}
mod scanner_impls {
    use super::*;
    macro_rules !iter_scan_impls {($($t :ty ) *) =>{$(impl IterScan for $t {type Output =Self ;#[inline ] fn scan <'a ,I :Iterator <Item =&'a str >>(iter :&mut I ) ->Option <Self >{iter .next () ?.parse ::<$t >() .ok () } } ) *} ;}
    iter_scan_impls !(char u8 u16 u32 u64 usize i8 i16 i32 i64 isize f32 f64 u128 i128 String ) ;
    macro_rules !iter_scan_tuple_impl {($($T :ident ) *) =>{impl <$($T :IterScan ) ,*>IterScan for ($($T ,) *) {type Output =($(<$T as IterScan >::Output ,) *) ;#[inline ] fn scan <'a ,It :Iterator <Item =&'a str >>(_iter :&mut It ) ->Option <Self ::Output >{Some (($($T ::scan (_iter ) ?,) *) ) } } } ;}
    iter_scan_tuple_impl!();
    iter_scan_tuple_impl!(A);
    iter_scan_tuple_impl !(A B ) ;
    iter_scan_tuple_impl !(A B C ) ;
    iter_scan_tuple_impl !(A B C D ) ;
    iter_scan_tuple_impl !(A B C D E ) ;
    iter_scan_tuple_impl !(A B C D E F ) ;
    iter_scan_tuple_impl !(A B C D E F G ) ;
    iter_scan_tuple_impl !(A B C D E F G H ) ;
    iter_scan_tuple_impl !(A B C D E F G H I ) ;
    iter_scan_tuple_impl !(A B C D E F G H I J ) ;
    iter_scan_tuple_impl !(A B C D E F G H I J K ) ;
    pub struct ScannerIter<'a, 'b, T> {
        inner: &'b mut Scanner<'a>,
        _marker: std::marker::PhantomData<fn() -> T>,
    }
    impl<'a, 'b, T: IterScan> Iterator for ScannerIter<'a, 'b, T> {
        type Item = <T as IterScan>::Output;
        fn next(&mut self) -> Option<Self::Item> {
            T::scan(&mut self.inner.iter)
        }
    }
    impl<'a> Scanner<'a> {
        #[inline]
        pub fn iter<'b, T: IterScan>(&'b mut self) -> ScannerIter<'a, 'b, T> {
            ScannerIter {
                inner: self,
                _marker: std::marker::PhantomData,
            }
        }
    }
}
pub mod marker {
    use super::*;
    pub struct Usize1;
    impl IterScan for Usize1 {
        type Output = usize;
        #[inline]
        fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output> {
            usize::scan(iter).map(|x| x.wrapping_sub(1))
        }
    }
    pub struct Isize1;
    impl IterScan for Isize1 {
        type Output = isize;
        #[inline]
        fn scan<'a, I: Iterator<Item = &'a str>>(iter: &mut I) -> Option<Self::Output> {
            isize::scan(iter).map(|x| x.wrapping_sub(1))
        }
    }
}
#[macro_export]
macro_rules !min {($e :expr ) =>{$e } ;($e :expr ,$($es :expr ) ,+) =>{std ::cmp ::min ($e ,min !($($es ) ,+) ) } ;}
#[macro_export]
macro_rules !chmin {($dst :expr ,$($src :expr ) ,+) =>{{let x =std ::cmp ::min ($dst ,min !($($src ) ,+) ) ;$dst =x ;} } ;}
#[macro_export]
macro_rules !max {($e :expr ) =>{$e } ;($e :expr ,$($es :expr ) ,+) =>{std ::cmp ::max ($e ,max !($($es ) ,+) ) } ;}
#[macro_export]
macro_rules !chmax {($dst :expr ,$($src :expr ) ,+) =>{{let x =std ::cmp ::max ($dst ,max !($($src ) ,+) ) ;$dst =x ;} } ;}
pub struct MergingUnionFind<T, F: Fn(&mut T, &mut T)> {
    cells: Vec<merging_union_find_impls::UFCell<T>>,
    merge: F,
}
mod merging_union_find_impls {
    use super::*;
    use std::cell::{Ref, RefCell, RefMut};
    use UFCell::*;
    #[derive(Clone, Debug)]
    pub enum UFCell<T> {
        Child(usize),
        Root(RefCell<RootData<T>>),
    }
    #[derive(Clone, Debug)]
    pub struct RootData<T> {
        pub data: T,
        pub size: usize,
    }
    impl<T> RootData<T> {
        pub fn new(data: T, size: usize) -> Self {
            Self { data, size }
        }
    }
    impl<T> UFCell<T> {
        pub fn is_root(&self) -> bool {
            match self {
                Self::Child(_) => false,
                Self::Root(_) => true,
            }
        }
    }
    impl<T, F: Fn(&mut T, &mut T)> MergingUnionFind<T, F> {
        pub fn new<I: Fn(usize) -> T>(n: usize, init: I, merge: F) -> Self {
            let cells: Vec<_> = (0..n)
                .map(|i| Root(RefCell::new(RootData::new(init(i), 1))))
                .collect();
            Self { cells, merge }
        }
        pub fn find(&mut self, x: usize) -> usize {
            let p = match &self.cells[x] {
                Child(p) => *p,
                Root(_) => return x,
            };
            let y = self.find(p);
            self.cells[x] = Child(y);
            y
        }
        pub fn find_root(&self, mut x: usize) -> Ref<RootData<T>> {
            loop {
                match &self.cells[x] {
                    Child(p) => x = *p,
                    Root(cell) => return cell.borrow(),
                }
            }
        }
        pub fn find_root_mut(&self, mut x: usize) -> RefMut<RootData<T>> {
            loop {
                match &self.cells[x] {
                    Child(p) => x = *p,
                    Root(cell) => return cell.borrow_mut(),
                }
            }
        }
        pub fn unite(&mut self, x: usize, y: usize) -> bool {
            let mut x = self.find(x);
            let mut y = self.find(y);
            if x == y {
                return false;
            }
            if self.size(x) < self.size(y) {
                std::mem::swap(&mut x, &mut y);
            }
            {
                let mut cx = self.find_root_mut(x);
                let mut cy = self.find_root_mut(y);
                (self.merge)(&mut cx.data, &mut cy.data);
                cx.size += cy.size;
            }
            self.cells[y] = Child(x);
            true
        }
        pub fn size(&mut self, x: usize) -> usize {
            self.find_root(x).size
        }
        pub fn same(&mut self, x: usize, y: usize) -> bool {
            self.find(x) == self.find(y)
        }
        pub fn members(&mut self, x: usize) -> Vec<usize> {
            let root = self.find(x);
            (0..self.cells.len())
                .filter(|i| self.find(*i) == root)
                .collect::<Vec<usize>>()
        }
        pub fn roots(&mut self) -> Vec<usize> {
            (0..self.cells.len())
                .filter(|&i| self.cells[i].is_root())
                .collect::<Vec<usize>>()
        }
        pub fn all_group_members(&mut self) -> std::collections::HashMap<usize, Vec<usize>> {
            let mut groups_map = std::collections::HashMap::new();
            for x in 0..self.cells.len() {
                let r = self.find(x);
                groups_map.entry(r).or_insert(vec![]).push(x);
            }
            groups_map
        }
    }
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Adjacent {
    pub id: usize,
    pub to: usize,
}
impl Adjacent {
    pub fn new(id: usize, to: usize) -> Adjacent {
        Adjacent { id, to }
    }
}
#[derive(Clone, Debug, Default)]
pub struct Graph {
    pub vsize: usize,
    pub esize: usize,
    pub graph: Vec<Vec<Adjacent>>,
}
impl Graph {
    pub fn new(vsize: usize) -> Graph {
        Graph {
            vsize,
            esize: 0,
            graph: vec![vec![]; vsize],
        }
    }
    pub fn add_edge(&mut self, from: usize, to: usize) {
        self.graph[from].push(Adjacent::new(self.esize, to));
        self.esize += 1;
    }
    pub fn add_undirected_edge(&mut self, u: usize, v: usize) {
        self.graph[u].push(Adjacent::new(self.esize, v));
        self.graph[v].push(Adjacent::new(self.esize, u));
        self.esize += 1;
    }
    pub fn vertices(&self) -> std::ops::Range<usize> {
        0..self.vsize
    }
    pub fn adjacency(&self, from: usize) -> &Vec<Adjacent> {
        &self.graph[from]
    }
    pub fn eid_cache(&self) -> GraphEidCache<'_> {
        let mut cache = vec![(0, 0); self.esize];
        for u in self.vertices() {
            for a in self.adjacency(u) {
                cache[a.id] = (u, a.to);
            }
        }
        GraphEidCache { graph: self, cache }
    }
}
pub struct GraphScanner<U: IterScan<Output = usize>, T: IterScan> {
    vsize: usize,
    esize: usize,
    directed: bool,
    _marker: std::marker::PhantomData<fn() -> (U, T)>,
}
impl<U: IterScan<Output = usize>, T: IterScan> GraphScanner<U, T> {
    pub fn new(vsize: usize, esize: usize, directed: bool) -> Self {
        Self {
            vsize,
            esize,
            directed,
            _marker: std::marker::PhantomData,
        }
    }
}
impl<U: IterScan<Output = usize>, T: IterScan> MarkedIterScan for GraphScanner<U, T> {
    type Output = (Graph, Vec<<T as IterScan>::Output>);
    fn mscan<'a, I: Iterator<Item = &'a str>>(self, iter: &mut I) -> Option<Self::Output> {
        let mut graph = Graph::new(self.vsize);
        let mut rest = Vec::with_capacity(self.esize);
        for _ in 0..self.esize {
            let (from, to) = (U::scan(iter)?, U::scan(iter)?);
            if self.directed {
                graph.add_edge(from, to);
            } else {
                graph.add_undirected_edge(from, to);
            }
            rest.push(T::scan(iter)?);
        }
        Some((graph, rest))
    }
}
#[derive(Debug, Clone)]
pub struct GraphEidCache<'a> {
    graph: &'a Graph,
    cache: Vec<(usize, usize)>,
}
impl<'a> std::ops::Index<usize> for GraphEidCache<'a> {
    type Output = (usize, usize);
    fn index(&self, index: usize) -> &Self::Output {
        &self.cache[index]
    }
}
fn main() {
    #[allow(unused_imports)]
    use std::io::{Read as _, Write as _};
    let __out = std::io::stdout();
    let mut __in_buf = String::new();
    std::io::stdin().read_to_string(&mut __in_buf).unwrap();
    let mut scanner = Scanner::new(&__in_buf);
    #[allow(unused_macros)]
    macro_rules !scan {() =>{scan !(usize ) } ;(($($t :tt ) ,*) ) =>{($(scan !($t ) ) ,*) } ;([$t :tt ;$len :expr ] ) =>{(0 ..$len ) .map (|_ |scan !($t ) ) .collect ::<Vec <_ >>() } ;({chars :$b :expr } ) =>{scanner .scan_chars_with ($b ) } ;({$t :tt =>$f :expr } ) =>{$f (scan !($t ) ) } ;(chars ) =>{scanner .scan_chars () } ;($t :ty ) =>{scanner .scan ::<$t >() } ;}
    let mut __out = std::io::BufWriter::new(__out.lock());
    #[allow(unused_macros)]
    macro_rules !print {($($arg :tt ) *) =>(::std ::write !(__out ,$($arg ) *) .unwrap () ) }
    #[allow(unused_macros)]
    macro_rules !println {($($arg :tt ) *) =>(::std ::writeln !(__out ,$($arg ) *) .unwrap () ) }
    #[allow(unused_macros)]
    macro_rules! echo {
        ($iter :expr ) => {
            echo!($iter, "\n")
        };
        ($iter :expr ,$sep :expr ) => {
            let mut iter = $iter;
            if let Some(item) = iter.next() {
                print!("{}", item);
            }
            for item in iter {
                print!("{}{}", $sep, item);
            }
            println!();
        };
    }
    let n = scan!();
    let m = scan!();
    let x = scan!([u64; n]);
    let (g, y) = scanner.mscan(GraphScanner::<Usize1, u64>::new(n, m, false));
    let mut uf = MergingUnionFind::new(n, |i| x[i], |x, y| *x += *y);
    let mut ok = vec![false; m];
    let mut idx: Vec<_> = (0..m).collect();
    idx.sort_by_key(|&i| y[i]);
    let edges = g.eid_cache();
    for &i in idx.iter() {
        let (a, b) = edges[i];
        uf.unite(a, b);
        ok[i] = uf.find_root(a).data >= y[i];
    }
    let mut r = GraphRec::new(n, m, y);
    for i in idx.into_iter().rev() {
        if ok[i] && !r.used[i] {
            r.dfs(edges[i].0, r.y[i], &g);
        }
    }
    println!("{}", r.used.iter().filter(|&&b| !b).count());
}
use marker::Usize1;
#[derive(Debug)]
pub struct GraphRec {
    pub n: usize,
    pub visited: Vec<bool>,
    used: Vec<bool>,
    y: Vec<u64>,
}
impl GraphRec {
    pub fn new(n: usize, m: usize, y: Vec<u64>) -> Self {
        Self {
            n,
            visited: vec![false; n],
            used: vec![false; m],
            y,
        }
    }
    pub fn dfs(&mut self, u: usize, y: u64, graph: &Graph) {
        self.visited[u] = true;
        for a in graph.adjacency(u) {
            if self.y[a.id] <= y {
                self.used[a.id] = true;
                if !self.visited[a.to] {
                    self.dfs(a.to, y, graph);
                }
            }
        }
    }
}

Measured memory_bytes: 25824