Problem:
Score : 400 points

Problem Statement

We have a permutation of the integers from 1 through N, p_1, p_2, .., p_N.
We also have M pairs of two integers between 1 and N (inclusive), represented as (x_1,y_1), (x_2,y_2), .., (x_M,y_M).
AtCoDeer the deer is going to perform the following operation on p as many times as desired so that the number of i (1 ≤ i ≤ N) such that p_i = i is maximized:

Choose j such that 1 ≤ j ≤ M, and swap p_{x_j} and p_{y_j}.

Find the maximum possible number of i such that p_i = i after operations.

Constraints

2 ≤ N ≤ 10^5

1 ≤ M ≤ 10^5

p is a permutation of integers from 1 through N.

1 ≤ x_j,y_j ≤ N

x_j ≠ y_j

If i ≠ j, \{x_i,y_i\} ≠ \{x_j,y_j\}.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N M
p_1 p_2 .. p_N
x_1 y_1
x_2 y_2
:
x_M y_M

Output

Print the maximum possible number of i such that p_i = i after operations.

Sample Input 1

5 2
5 3 1 4 2
1 3
5 4

Sample Output 1

2

If we perform the operation by choosing j=1, p becomes 1 3 5 4 2, which is optimal, so the answer is 2.

Sample Input 2

3 2
3 2 1
1 2
2 3

Sample Output 2

3

If we perform the operation by, for example, choosing j=1, j=2, j=1 in this order, p becomes 1 2 3, which is obviously optimal.
Note that we may choose the same j any number of times.

Sample Input 3

10 8
5 3 6 8 7 10 9 1 2 4
3 1
4 1
5 9
2 5
6 5
3 5
8 9
7 9

Sample Output 3

8

Sample Input 4

5 1
1 2 3 4 5
1 5

Sample Output 4

5

We do not have to perform the operation.

Solution in Rust (1.15.1) (judge verdict: Accepted)

extern crate core;

use std::io::{self, Read};

#[macro_use]
mod parser {
    macro_rules! input {
    ($s:expr=>$($t:tt)*) => {
        let mut lines=$s.split("\n");
        $(
            line_parse!(lines,$t);
        )*
    };
    }

    macro_rules! line_parse {
    ($lines:expr,($($name:ident:$t:tt)*)) => {
        let mut line=$lines.next().unwrap().split_whitespace();
        $(value_def!(line,$name,$t);)*
    };

    //複数行
    ($lines:expr,{$n:expr;$name:ident:$t:tt}) => {
        values_def!($lines,$n,$name,$t);
    };
    }

    macro_rules! value_def {
    ($line:expr,$name:ident,$t:tt) => {
        let $name=value!($line,$t);
    };
    }

    macro_rules! values_def {
    ($lines:expr,$n:expr,$name:ident,$t:tt) => {
        let $name={
        let mut vec=Vec::new();
        for i in 0..$n{
            let mut next=$lines.next().unwrap().split_whitespace();
            vec.push(value!(next,$t));
        }
        vec
        };
    };
    }

    macro_rules! value {
    //配列
    ($line:expr,[$t:tt]) => {
        $line.map(|x|{
        let mut iter=::std::iter::once(x);
        value!(iter,$t)
        }).collect::<Vec<_>>()
    };
    //タプル
    ($line:expr,($($t:tt),*)) => {
        ($(value!($line,$t),)*)
    };
    //文字列
    ($line:expr,#) => {
        $line.next().unwrap()
    };
    //単一値
    ($line:expr,$t:ty) => {
        $line.next().unwrap().parse::<$t>().unwrap()
    };
    }
}

fn main() {
    let mut input = String::new();
    io::stdin().read_to_string(&mut input).unwrap();
    let output = solve(input.trim().to_string());
    println!("{}", output);
}

fn solve(input: String) -> String {
    input!(input=>(n:usize m:usize)(p:[usize]){m;swap:(usize,usize)});
    let swap = swap.into_iter()
        .map(|(a, b)| (a - 1, b - 1))
        .collect::<Vec<_>>();
    let p = p.into_iter().map(|x| x - 1).collect::<Vec<_>>();

    //逆vec(値→index)
    /*let mut find_vec = Vec::with_capacity(n);
    find_vec.resize(n, 0);
    for i in 0..n {
        find_vec[p[i]] = i;
    }*/

    let mut uf = uf::UnionFind::new(n);
    for (x, y) in swap {
        uf.unite(x, y);
    }

    let mut count = 0;

    for i in 0..n {
        if i == p[i] || uf.same(i, p[i]) {
            count += 1;
        }
    }

    /*let edges = swap.into_iter()
        .flat_map(|(a, b)| vec![(a, b, 1), (b, a, 1)])
        .collect::<Vec<_>>();
    let mut graph = graph::ListGraph::from(graph::FlatGraph(n, edges));*/

    count.to_string()
}

mod uf {
    #[derive(PartialEq, Debug, Clone)]
    pub struct UnionFindNode {
        pub par: usize,
        pub rank: usize,
    }

    #[derive(PartialEq, Debug, Clone)]
    pub struct UnionFind(pub Vec<UnionFindNode>);

    impl UnionFind {
        //初期化
        pub fn new(size: usize) -> UnionFind {
            let mut vec = Vec::new();
            for i in 0..size {
                vec.push(UnionFindNode { par: i, rank: 0 });
            }

            UnionFind(vec)
        }

        //根を求める
        pub fn find(&mut self, x: usize) -> usize {
            if self.0[x].par == x {
                x
            } else {
                let par = self.0[x].par;
                let v = self.find(par);
                self.0[x].par = v;
                v
            }
        }

        //xとyの集合を併合
        pub fn unite(&mut self, x: usize, y: usize) {
            let x = self.find(x);
            let y = self.find(y);
            if x == y {
                return;
            }

            if self.0[x].rank < self.0[y].rank {
                self.0[x].par = y;
            } else {
                self.0[y].par = x;
                if self.0[x].rank == self.0[y].rank {
                    self.0[x].rank += 1;
                }
            }
        }

        //xとyが同じ集合に属するか
        pub fn same(&mut self, x: usize, y: usize) -> bool {
            self.find(x) == self.find(y)
        }
    }

    #[cfg(test)]
    mod tests {
        use super::*;

        #[test]
        fn new() {
            assert_eq!(
                UnionFind(vec![
                    UnionFindNode { par: 0, rank: 0 },
                    UnionFindNode { par: 1, rank: 0 },
                    UnionFindNode { par: 2, rank: 0 },
                ]),
                UnionFind::new(3)
            );
        }

        #[test]
        fn find() {
            let mut uf = UnionFind(vec![
                UnionFindNode { par: 0, rank: 1 },
                UnionFindNode { par: 0, rank: 0 },
                UnionFindNode { par: 1, rank: 0 },
                UnionFindNode { par: 3, rank: 0 },
                UnionFindNode { par: 4, rank: 0 },
            ]);

            {
                let mut uf = uf.clone();
                assert_eq!(0, uf.find(0));
                assert_eq!(
                    UnionFind(vec![
                        UnionFindNode { par: 0, rank: 1 },
                        UnionFindNode { par: 0, rank: 0 },
                        UnionFindNode { par: 1, rank: 0 },
                        UnionFindNode { par: 3, rank: 0 },
                        UnionFindNode { par: 4, rank: 0 },
                    ]),
                    uf
                );
            }

            {
                let mut uf = uf.clone();
                assert_eq!(0, uf.find(1));
                assert_eq!(
                    UnionFind(vec![
                        UnionFindNode { par: 0, rank: 1 },
                        UnionFindNode { par: 0, rank: 0 },
                        UnionFindNode { par: 1, rank: 0 },
                        UnionFindNode { par: 3, rank: 0 },
                        UnionFindNode { par: 4, rank: 0 },
                    ]),
                    uf
                );
            }
            {
                let mut uf = uf.clone();
                for _ in 0..2 {
                    assert_eq!(0, uf.find(2));
                    assert_eq!(
                        UnionFind(vec![
                            UnionFindNode { par: 0, rank: 1 },
                            UnionFindNode { par: 0, rank: 0 },
                            UnionFindNode { par: 0, rank: 0 },
                            UnionFindNode { par: 3, rank: 0 },
                            UnionFindNode { par: 4, rank: 0 },
                        ]),
                        uf
                    );
                }
            }

            {
                let mut uf = uf.clone();
                assert_eq!(4, uf.find(4));
                assert_eq!(
                    UnionFind(vec![
                        UnionFindNode { par: 0, rank: 1 },
                        UnionFindNode { par: 0, rank: 0 },
                        UnionFindNode { par: 1, rank: 0 },
                        UnionFindNode { par: 3, rank: 0 },
                        UnionFindNode { par: 4, rank: 0 },
                    ]),
                    uf
                );
            }
        }

        #[test]
        fn unite() {
            let mut uf = UnionFind(vec![
                UnionFindNode { par: 0, rank: 0 },
                UnionFindNode { par: 1, rank: 0 },
                UnionFindNode { par: 2, rank: 0 },
                UnionFindNode { par: 3, rank: 0 },
                UnionFindNode { par: 4, rank: 0 },
            ]);

            uf.unite(2, 2);
            assert_eq!(
                UnionFind(vec![
                    UnionFindNode { par: 0, rank: 0 },
                    UnionFindNode { par: 1, rank: 0 },
                    UnionFindNode { par: 2, rank: 0 },
                    UnionFindNode { par: 3, rank: 0 },
                    UnionFindNode { par: 4, rank: 0 },
                ]),
                uf
            );

            for _ in 0..2 {
                uf.unite(0, 1);
                assert_eq!(
                    UnionFind(vec![
                        UnionFindNode { par: 0, rank: 1 },
                        UnionFindNode { par: 0, rank: 0 },
                        UnionFindNode { par: 2, rank: 0 },
                        UnionFindNode { par: 3, rank: 0 },
                        UnionFindNode { par: 4, rank: 0 },
                    ]),
                    uf
                );
            }

            uf.unite(3, 1);
            assert_eq!(
                UnionFind(vec![
                    UnionFindNode { par: 0, rank: 1 },
                    UnionFindNode { par: 0, rank: 0 },
                    UnionFindNode { par: 2, rank: 0 },
                    UnionFindNode { par: 0, rank: 0 },
                    UnionFindNode { par: 4, rank: 0 },
                ]),
                uf
            );

            uf.unite(0, 4);
            assert_eq!(
                UnionFind(vec![
                    UnionFindNode { par: 0, rank: 1 },
                    UnionFindNode { par: 0, rank: 0 },
                    UnionFindNode { par: 2, rank: 0 },
                    UnionFindNode { par: 0, rank: 0 },
                    UnionFindNode { par: 0, rank: 0 },
                ]),
                uf
            );
        }

        #[test]
        fn same() {
            let mut uf = UnionFind(vec![
                UnionFindNode { par: 0, rank: 0 },
                UnionFindNode { par: 0, rank: 1 },
                UnionFindNode { par: 2, rank: 0 },
                UnionFindNode { par: 3, rank: 0 },
                UnionFindNode { par: 4, rank: 0 },
            ]);

            assert_eq!(true, uf.same(0, 1));
            assert_eq!(true, uf.same(1, 0));
            assert_eq!(false, uf.same(1, 3));
        }
    }
}

mod graph {
    pub type NodeId = usize;

    pub type Cost = i64;

    pub type Node = Vec<Edge>;

    pub type Edge = (NodeId, NodeId, Cost);

    #[derive(PartialEq, Debug, Clone)]
    pub struct MatrixGraph(pub Vec<Vec<Option<Cost>>>);

    impl From<Vec<Vec<Option<Cost>>>> for MatrixGraph {
        fn from(data: Vec<Vec<Option<Cost>>>) -> MatrixGraph {
            MatrixGraph(data)
        }
    }

    impl From<ListGraph> for MatrixGraph {
        fn from(graph: ListGraph) -> MatrixGraph {
            FlatGraph::from(graph).into()
        }
    }

    impl From<FlatGraph> for MatrixGraph {
        fn from(FlatGraph(len, data): FlatGraph) -> MatrixGraph {
            let mut vec = Vec::with_capacity(len);
            vec.resize(len, {
                let mut v = Vec::with_capacity(len);
                v.resize(len, None);
                v
            });

            for (from, to, cost) in data {
                vec[from][to] = Some(cost);
            }

            vec.into()
        }
    }

    #[derive(PartialEq, Debug, Clone)]
    pub struct ListGraph(pub Vec<Vec<Edge>>);

    impl From<Vec<Vec<(NodeId, Cost)>>> for ListGraph {
        fn from(data: Vec<Vec<(NodeId, Cost)>>) -> ListGraph {
            ListGraph(
                data.into_iter()
                    .enumerate()
                    .map(|(from, edges)| {
                        edges
                            .into_iter()
                            .map(|(to, cost)| (from, to, cost))
                            .collect()
                    })
                    .collect(),
            )
        }
    }

    impl From<Vec<Vec<Edge>>> for ListGraph {
        fn from(data: Vec<Vec<Edge>>) -> ListGraph {
            ListGraph(data)
        }
    }

    impl From<FlatGraph> for ListGraph {
        fn from(FlatGraph(len, data): FlatGraph) -> ListGraph {
            let mut vec = Vec::with_capacity(len);
            vec.resize(len, Vec::new());

            for (from, to, cost) in data {
                vec[from].push((from, to, cost));
            }

            ListGraph(vec)
        }
    }

    impl From<MatrixGraph> for ListGraph {
        fn from(graph: MatrixGraph) -> ListGraph {
            FlatGraph::from(graph).into()
        }
    }

    #[derive(PartialEq, Debug, Clone)]
    pub struct FlatGraph(pub usize, pub Vec<Edge>);

    impl From<ListGraph> for FlatGraph {
        fn from(ListGraph(data): ListGraph) -> FlatGraph {
            let len = data.len();
            (len, data.into_iter().flat_map(|x| x).collect::<Vec<_>>()).into()
        }
    }

    impl From<(usize, Vec<(NodeId, NodeId, Cost)>)> for FlatGraph {
        fn from((len, data): (usize, Vec<(NodeId, NodeId, Cost)>)) -> FlatGraph {
            FlatGraph(len, data)
        }
    }

    impl From<MatrixGraph> for FlatGraph {
        fn from(MatrixGraph(data): MatrixGraph) -> FlatGraph {
            let mut vec = Vec::new();
            let len = data.len();

            for (from, v) in data.into_iter().enumerate() {
                for (to, cost) in v.into_iter().enumerate() {
                    if let Some(cost) = cost {
                        vec.push((from, to, cost));
                    }
                }
            }

            (len, vec).into()
        }
    }

    #[derive(PartialEq, Debug, Clone)]
    pub struct MazeID(pub Vec<Vec<Option<usize>>>);
    impl From<MazeID> for ListGraph {
        fn from(MazeID(maze): MazeID) -> ListGraph {
            if maze.len() == 0 {
                return ListGraph(Vec::new());
            }

            let h = maze.len();
            let w = maze[0].len();

            let mut graph = Vec::new();
            for y in 0..h {
                for x in 0..w {
                    if let Some(_) = maze[y][x] {
                        let mut edges = Vec::new();
                        if y != 0 {
                            if let Some(to) = maze[y - 1][x] {
                                edges.push((to, 1));
                            }
                        }
                        if x != 0 {
                            if let Some(to) = maze[y][x - 1] {
                                edges.push((to, 1));
                            }
                        }
                        if x != w - 1 {
                            if let Some(to) = maze[y][x + 1] {
                                edges.push((to, 1));
                            }
                        }
                        if y != h - 1 {
                            if let Some(to) = maze[y + 1][x] {
                                edges.push((to, 1));
                            }
                        }
                        graph.push(edges);
                    }
                }
            }
            ListGraph::from(graph)
        }
    }

    //迷路
    #[derive(PartialEq, Debug, Clone)]
    pub struct Maze(pub Vec<Vec<bool>>);

    impl From<Maze> for MazeID {
        fn from(Maze(maze): Maze) -> MazeID {
            let mut id = 0;
            MazeID(
                maze.into_iter()
                    .map(|vec| {
                        vec.into_iter()
                            .map(|x| {
                                if x {
                                    let res: Option<usize> = Some(id);
                                    id += 1;
                                    res
                                } else {
                                    None
                                }
                            })
                            .collect::<Vec<_>>()
                    })
                    .collect::<Vec<_>>(),
            )
        }
    }

    #[cfg(test)]
    mod tests {
        use super::*;

        #[test]
        fn list_to_matrix() {
            assert_eq!(
                MatrixGraph(vec![
                    vec![None, Some(1), None, Some(3)],
                    vec![Some(10), Some(1), None, None],
                    vec![None, None, Some(5), None],
                    vec![None, None, None, None],
                ]),
                MatrixGraph::from(ListGraph(vec![
                    vec![(0, 1, 1), (0, 3, 3)],
                    vec![(1, 0, 10), (1, 1, 1)],
                    vec![(2, 2, 5)],
                    vec![],
                ]))
            );
        }

        #[test]
        fn flat_to_matrix() {
            assert_eq!(
                MatrixGraph(vec![
                    vec![None, Some(1), None, Some(3)],
                    vec![Some(10), Some(1), None, None],
                    vec![None, None, Some(5), None],
                    vec![None, None, None, None],
                ]),
                MatrixGraph::from(FlatGraph(
                    4,
                    vec![(0, 1, 1), (0, 3, 3), (1, 0, 10), (1, 1, 1), (2, 2, 5)]
                ))
            );
        }

        #[test]
        fn data_to_list() {
            assert_eq!(
                ListGraph(vec![
                    vec![(0, 1, 1), (0, 3, 3)],
                    vec![(1, 0, 10), (1, 1, 1)],
                    vec![(2, 2, 5)],
                    vec![],
                ]),
                ListGraph::from(vec![
                    vec![(1, 1), (3, 3)],
                    vec![(0, 10), (1, 1)],
                    vec![(2, 5)],
                    vec![],
                ])
            );
        }

        #[test]
        fn flat_to_list() {
            assert_eq!(
                ListGraph(vec![
                    vec![(0, 1, 1), (0, 3, 3)],
                    vec![(1, 0, 10), (1, 1, 1)],
                    vec![(2, 2, 5)],
                    vec![],
                ]),
                ListGraph::from(FlatGraph(
                    4,
                    vec![(0, 1, 1), (0, 3, 3), (1, 0, 10), (1, 1, 1), (2, 2, 5)]
                ))
            );
        }

        #[test]
        fn list_to_flat() {
            assert_eq!(
                FlatGraph(
                    4,
                    vec![(0, 1, 1), (0, 3, 3), (1, 0, 10), (1, 1, 1), (2, 2, 5)]
                ),
                FlatGraph::from(ListGraph(vec![
                    vec![(0, 1, 1), (0, 3, 3)],
                    vec![(1, 0, 10), (1, 1, 1)],
                    vec![(2, 2, 5)],
                    vec![],
                ]))
            );
        }

        #[test]
        fn mtrix_to_flat() {
            assert_eq!(
                FlatGraph(
                    4,
                    vec![(0, 1, 1), (0, 3, 3), (1, 0, 10), (1, 1, 1), (2, 2, 5)]
                ),
                FlatGraph::from(MatrixGraph(vec![
                    vec![None, Some(1), None, Some(3)],
                    vec![Some(10), Some(1), None, None],
                    vec![None, None, Some(5), None],
                    vec![None, None, None, None],
                ]))
            );
        }

        #[test]
        fn maze_id_to_list() {
            assert_eq!(
                ListGraph(vec![
                    vec![(0, 2, 1)],
                    vec![(1, 4, 1)],
                    vec![(2, 0, 1), (2, 3, 1), (2, 6, 1)],
                    vec![(3, 2, 1), (3, 4, 1)],
                    vec![(4, 1, 1), (4, 3, 1), (4, 5, 1), (4, 7, 1)],
                    vec![(5, 4, 1)],
                    vec![(6, 2, 1)],
                    vec![(7, 4, 1)],
                ]),
                ListGraph::from(MazeID::from(Maze(vec![
                    vec![true, false, true, false],
                    vec![true, true, true, true],
                    vec![true, false, true, false],
                ])))
            );
        }

        #[test]
        fn maze_to_maze_id() {
            assert_eq!(
                MazeID(vec![
                    vec![Some(0), None, Some(1), None],
                    vec![Some(2), Some(3), Some(4), Some(5)],
                    vec![Some(6), None, Some(7), None],
                ]),
                MazeID::from(Maze(vec![
                    vec![true, false, true, false],
                    vec![true, true, true, true],
                    vec![true, false, true, false],
                ]))
            );
        }
    }
}

macro_rules! tests {
    ($($name:ident: $input:expr=>$output:expr,)*) => {
        mod tests {
            $(
                #[test]
                fn $name() {
                    assert_eq!($output.trim().to_string(),super::solve($input.trim().to_string()));
                }
            )*
        }
    }
}

tests! {
    test1: "5 2\n5 3 1 4 2\n1 3\n5 4" => "2",
    test2: "3 2\n3 2 1\n1 2\n2 3" => "3",
    test3: "10 8\n5 3 6 8 7 10 9 1 2 4\n3 1\n4 1\n5 9\n2 5\n6 5\n3 5\n8 9\n7 9" => "8",
    test4: "5 1\n1 2 3 4 5\n1 5" => "5",
}