use std::cmp::*;
use std::collections::*;
use std::io::*;
use std::str::FromStr;
use utils::*;

pub fn main() {
    let i = stdin();
    let mut o = Vec::new();
    run(i.lock(), &mut o);
    stdout().write_all(&o).unwrap();
}

fn run<R: BufRead, W: Write>(i: R, o: &mut W) {
    let mut i = AtRead::from(i);
    let (n, m) = i.read2::<usize, usize>();
    let mut p = i.read_vec::<usize>(n);
    let mut xys = Vec::new();
    for _ in 0..m {
        let xy = i.read2::<usize, usize>();
        xys.push((xy.0 - 1, xy.1 - 1));
    }
    for p in p.iter_mut() {
        *p -= 1;
    }

    writeln!(o, "{}", solve(&p, &xys)).unwrap();
}
fn solve(p: &[usize], xy: &[(usize, usize)]) -> usize {
    let mut visit = vec![false; p.len()];
    let mut edges = vec![Vec::new(); p.len()];
    let mut result = 0;

    for &xy in xy {
        edges[xy.0].push(xy.1);
        edges[xy.1].push(xy.0);
    }
    let mut q = Vec::new();
    let mut idxs = HashSet::new();
    for i in 0..p.len() {
        if visit[i] {
            continue;
        }
        visit[i] = true;
        let e = &edges[i];
        if e.is_empty() {
            if p[i] == i {
                result += 1;
            }
        } else {
            q.push(i);
            while let Some(i0) = q.pop() {
                idxs.insert(i0);
                for &i1 in &edges[i0] {
                    if visit[i1] {
                        continue;
                    }
                    visit[i1] = true;
                    q.push(i1);
                }
            }
            for &idx in &idxs {
                if idxs.contains(&p[idx]) {
                    result += 1;
                }
            }
            idxs.clear();
        }
    }

    result
}

mod utils {
    #![allow(dead_code)]
    use super::*;
    use std::ops::*;

    pub struct AtRead<R: BufRead> {
        r: R,
        s: String,
    }

    macro_rules! fn_read {
        {$f:ident($($v:ident: $t:ident),*)} => {
            pub fn $f<$($t: FromStr),*>(&mut self) -> ($($t),*) {
                let i = &mut self.read_line().split(' ');
                $(
                    let $v = next(i);
                )*
                ($($v),*)
            }
        };
    }

    impl<R: BufRead> AtRead<R> {
        pub fn from(r: R) -> Self {
            AtRead {
                r: r,
                s: String::new(),
            }
        }
        pub fn read_line(&mut self) -> &str {
            self.s.clear();
            self.r.read_line(&mut self.s).unwrap();
            self.s.trim()
        }

        pub fn read<T: FromStr>(&mut self) -> T {
            self.read_line().parse().ok().unwrap()
        }
        fn_read! { read2(v1: T1, v2: T2) }
        fn_read! { read3(v1: T1, v2: T2, v3: T3) }
        fn_read! { read4(v1: T1, v2: T2, v3: T3, v4: T4) }
        fn_read! { read5(v1: T1, v2: T2, v3: T3, v4: T4, v5: T5) }

        pub fn read_vec<T: FromStr>(&mut self, n: usize) -> Vec<T> {
            self.read_line()
                .split(' ')
                .take(n)
                .map(|x| x.parse().ok().unwrap())
                .collect()
        }
        pub fn read_array<A: AsMut<[T]> + Default, T: FromStr>(&mut self) -> A {
            let mut a: A = Default::default();
            {
                let a: &mut [T] = a.as_mut();
                let i = &mut self.read_line().split(' ');
                for n in 0..a.len() {
                    a[n] = next(i);
                }
            }
            a
        }
    }

    fn next<'a, T: FromStr, I: std::iter::Iterator<Item = &'a str>>(i: &mut I) -> T {
        i.next().unwrap().parse().ok().unwrap()
    }
}


Measured memory_bytes: 20732