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 C# (Mono 4.6.2.0) (judge verdict: Time Limit Exceeded)

using System;
using System.Collections;
using System.Collections.Generic;
using static Exter;
using System.Linq;
using System.Numerics;
#if DEBUG
#else
using console = System.Console;
#endif

public class App
{
    public static void Main(string[] args)
    {
        int n,m;
        {
            var r = readarr;
            n=r[0];m=r[1];
        }
        var p = readarr;
        int[] ufa = new int[n];
        for(int i = 0;i<n;i++)
            ufa[i] = -1;
        
        for(int j = 0;j<m;j++)
        {
            int a,b;
            {
                var r = readarr;
                a=r[0];b=r[1];
                a--;
                b--;
            }
            while(ufa[a] >= 0)
                a=ufa[a];
            while(ufa[b] >= 0)
                b=ufa[b];
            if(ufa[a]>ufa[b])
            {
                a = a^b;
                b = a^b;
                a = a^b;
            }
            ufa[a]=Min(ufa[a],ufa[b]-1);
            ufa[b]=a;
        }
        int c = 0;
        for(int i = 0;i<n;i++)
        {
            p[i]--;
            int a = i;
            int b = p[i];
            while(ufa[a] >= 0)
                a=ufa[a];
            while(ufa[b] >= 0)
                b=ufa[b];
            if(a==b)
                c++;
        }
        cout = c;
    }
    public string[] SnRead(int n)
    {
        var v = new string[n];
        for(int i = 0;i<n;i++)
            v[i] = console.ReadLine();
        return v;
    }
    public char[,] RectCharRead(int h,int w)
    {
        var v = new char[h,w];
        for(int i = 0;i < h;i++)
        {
            var s = console.ReadLine();
            for(int j = 0;j < w;j++)
            {
                v[i,j] = s[j];
            }
        }
        return v;
    }
    public bool[,] RectCharToBool(int h,int w)
    {
        var v = new bool[h,w];
        for(int i = 0;i < h;i++)
        {
            var s = console.ReadLine();
            for(int j = 0;j < w;j++)
            {
                v[i,j] = s[j] == '.';
            }
        }
        return v;
    }
    public class BiasedArray<Type>
    {
        private Type[] ContainedValue;
        public bool ReturnDefaultIfOutOfRange = true;
        public bool IgnoreSetIfOutOfRange = true;
        public Type DefaultValue = default(Type);
        public int Length;
        BiasedArray(int length)
        {
            Length = length;
            ContainedValue = new Type[length];
        }
        public bool IsWithinRange(int x)=>0<=x&&x<Length;
        public Type this[int x]
        {
            get
            {
                if(IsWithinRange(x))
                    return ContainedValue[x];
                else if(ReturnDefaultIfOutOfRange)
                    return DefaultValue;
                else
                    throw new IndexOutOfRangeException();
            }
            set
            {
                if(IsWithinRange(x))
                    ContainedValue[x] = value;
                else if(!IgnoreSetIfOutOfRange)
                    throw new IndexOutOfRangeException();
            }
        }
    }
    public class BiasedArray2<Type>
    {
        private Type[,] ContainedValue;
        public bool ReturnDefaultIfOutOfRange = true;
        public bool IgnoreSetIfOutOfRange = true;
        public Type DefaultValue = default(Type);
        public int Width;
        public int Height;
        BiasedArray2(int width,int height)
        {
            Width = width;
            Height = height;
            ContainedValue = new Type[width,height];
        }
        public bool IsWithinRange(int x,int y)=>0<=x&&x<Width&&0<=y&&y<Height;
        public Type this[int x,int y]
        {
            get
            {
                if(IsWithinRange(x,y))
                    return ContainedValue[x,y];
                else if(ReturnDefaultIfOutOfRange)
                    return DefaultValue;
                else
                    throw new IndexOutOfRangeException();
            }
            set
            {
                if(IsWithinRange(x,y))
                    ContainedValue[x,y] = value;
                else if(!IgnoreSetIfOutOfRange)
                    throw new IndexOutOfRangeException();
            }
        }
    }
    public class BiasedArray3<Type>
    {
        private Type[,,] ContainedValue;
        public bool ReturnDefaultIfOutOfRange = true;
        public bool IgnoreSetIfOutOfRange = true;
        public Type DefaultValue = default(Type);
        public int Width;
        public int Depth;
        public int Height;
        BiasedArray3(int width,int depth,int height)
        {
            Width = width;
            Depth = depth;
            Height = height;
            ContainedValue = new Type[width,depth,height];
        }
        public bool IsWithinRange(int x,int y,int z)=>0<=x&&x<Width&&0<=y&&y<Depth&&0<=z&&z<Height;
        public Type this[int x,int y,int z]
        {
            get
            {
                if(IsWithinRange(x,y,z))
                    return ContainedValue[x,y,z];
                else if(ReturnDefaultIfOutOfRange)
                    return DefaultValue;
                else
                    throw new IndexOutOfRangeException();
            }
            set
            {
                if(IsWithinRange(x,y,z))
                    ContainedValue[x,y,z] = value;
                else if(!IgnoreSetIfOutOfRange)
                    throw new IndexOutOfRangeException();
            }
        }
    }
    public static long Lcm(long a, long b)=>a*b/Gcd(a,b);
    public static long Gcd(long a, long b)=>a > b ? GcdRecursive(a, b) : GcdRecursive(b, a);
    private static long GcdRecursive(long a, long b){if(b == 0) return a; return GcdRecursive(b, a % b);}
}
public class RollingHash
{
    long[] h;
    long m = 2147483647;
    int b = 524287;
    Power baser;
    public RollingHash(string s)
    {
        baser = new Power(b);
        h = new long[s.Length];
        h[0] = 0;
        for(int i = 1;i < s.Length;i++)
        {
            h[i] = (h[i-1] * b + s[i]) % m;
        }
    }
    public long Calc(int l,int r)
    {
        cout = h[r];
        cout = h[l] * baser.GetEntry(r-l-1);
        return 0;
    }
}
public class PriorityQueue<T> : IEnumerable<T> where T : IComparable
        {
            List<T> buffer = new List<T>();
            static void PushHeap(List<T> array, T elem)
            {
                int n = array.Count;
                array.Add(elem);
 
                while (n != 0)
                {
                    int i = (n - 1) / 2;
                    if (array[n].CompareTo(array[i]) < 0)
                    {
                        T tmp = array[n]; array[n] = array[i]; array[i] = tmp;
                    }
                    n = i;
                }
            }
            static void PopHeap(List<T> array)
            {
                int n = array.Count - 1;
                array[0] = array[n];
                array.RemoveAt(array.Count - 1);
 
                for (int i = 0, j; (j = 2 * i + 1) < n;)
                {
                    if ((j != n - 1) && (array[j].CompareTo(array[j + 1]) > 0))
                        j++;
                    if (array[i].CompareTo(array[j]) > 0)
                    {
                        T tmp = array[j]; array[j] = array[i]; array[i] = tmp;
                    }
                    i = j;
                }
            }
            public int Count
            {
                get
                {
                    return buffer.Count;
                }
            }
            public void Push(T elem)
            {
                PushHeap(this.buffer, elem);
            }
            public T Peek()
            {
                return buffer[0];
            }
 
            public T Pop()
            {
                T a = buffer[0];
                PopHeap(this.buffer);
                return a;
            }
            public IEnumerator<T> GetEnumerator()
            {
                var v = new List<T>(buffer);
                while(v.Count != 0)
                {
                    yield return v[0];
                    PopHeap(v);
                }
            }
            IEnumerator IEnumerable.GetEnumerator()
            {
                return this.GetEnumerator();
            }
        }
public class Power
    {
        public int Base;
        private List<long> Value = new List<long>();
        public Power(int v)
        {
            if(v==1)
                new ArgumentOutOfRangeException();
            long prev = -1;
            long g = v;
            Base = v;
            
            while(g > prev)
            {
                Value.Add(g);
                prev = g;
                g *= g;
            }
        }
        public long GetEntry(int exponent)
        {
            long s = 1;
            for(int i = 0;(1<<i)<=exponent;i++)
            {
                if((exponent & (1<<i)) != 0)
                {
                    s *= Value[i];
                }
            }
            return s;
        }
    }
public static class Exter
{
    public static IEnumerable<long> PrimeFactors(long n)
    {
        int i = 2;
        long tmp = n;

        while (i * i <= n)
        {
            if(tmp % i == 0){
                tmp /= i;
                yield return i;
            }else{
                i++;
            }
        }
        if(tmp != 1) yield return tmp;
    }
    public class LoopArray<T>
    {
        public readonly int Length;
        private T[] arr;
        public LoopArray(int Capacity)
        {
            Length = Capacity;
        }
        public LoopArray(T[] ar)
        {
            arr = new T[ar.Length];
            Array.Copy(ar,arr,ar.Length);
        }
    }
    public class Point
    {
        public Point(long cx, long cy)
        {
            x = cx;
            y = cy;
        }
        public long x;
        public long y;
    }
    public static IEnumerable<Result> ListAll<T1,T2,Result>(IEnumerable<T1> a,IEnumerable<T2> b,Func<T1,T2,Result> f)
    {
        foreach(var v in a)
        {
            foreach(var w in b)
               yield return f(v,w);
        }
    }
    public static IEnumerable<Result> ListAll<T1,T2,Result>(IEnumerable<T1> a,IEnumerable<T2> b,Func<T1,T2,Result> f,Func<T1,T2,bool> s)
    {
        foreach(var v in a)
        {
            foreach(var w in b)
               if(s(v,w)) yield return f(v,w);
        }
    }
    public static int ToInt(this long v)=>(int)v;
    public static int ToInt(this string v)=>int.Parse(v);
    public static int Max(params int[] p)=>p.Max();
    public static long Max(params long[] p)=>p.Max();
    public static int Min(params int[] p)=>p.Min();
    public static long Min(params long[] p)=>p.Min();
    public static int Gcd(int a, int b)=>a > b ? GcdRecursive(a, b) : GcdRecursive(b, a);
    private static int GcdRecursive(int a, int b)=>b == 0 ? a : GcdRecursive(b, a % b);
    public static object cout
    {
        set
        {
            console.Write(value.ToString());
            console.WriteLine();
            
        }
    }
    public static void ToCout<t>(this IEnumerable<t> v)
    {
        cout = string.Join(",",v);
    }
    public static int[] readarr
    {
        get 
        {
            preadarr = console.ReadLine().Split().Select(s=>int.Parse(s)).ToArray();
            return preadarr;
        }
    }
    public static int[] preadarr;
}


#if DEBUG
public static class console
{
    static int cursorLine = 0;
    static readonly string[] cin = System.IO.File.ReadAllLines("Input.txt");
    static public string ReadLine()
    { 
        if(cursorLine == cin.Length)
            cout = "Out";
        return cin[cursorLine++];
    }
    static public void WriteLine()
    {
        Console.WriteLine();
    }
    static public void WriteLine<T>(T input)
    {
        Console.WriteLine(input);
    }
    static public void Write<T>(T input)
    {
        Console.Write(input);
    }
    static public void WriteLine(string s,params object[] arr)
    {
        Console.WriteLine(s,arr);
    }
}
#endif