//Template by _Trung_Nguyen
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections;
using System.IO;

using Libraries;
using Libraries.IO;
using Libraries.Collections;

namespace Codeforces
{
	public class sample
	{
		private static int solution()
		{
			int n = cin.ReadInt32();

			int [] f = cin.ReadInt32Array();
			for (int i = 0; i < n; ++i) --f[i];

			int [] from = Arrays.Fill(n, -1).ToArray();

			for (int i = 0; i < n; ++i) from[f[i]] = i;

			bool [] visited = new bool[n];

			List<int> start = new List<int>();
			List<int> end = new List<int>();

			for (int i = 0; i < n; ++i)
			{
				if (from[i] != -1) continue;
				if (visited[i]) continue;

				start.Add(i);

				int current = i;
				while (!visited[f[current]])
				{
					visited[current] = true;
					current = f[current];
				}

				visited[current] = true;

				end.Add(current);
			}

			int k = start.Count;
			cout.WriteLine(k);

			for (int i = 0; i < k; ++i)
			{
				cout.WriteLine("{0} {1}", end[i] + 1, start[(i + 1) % k] + 1);
			}

			return 0;
		}

//===============Prewritten code======================
		private static istream cin = new istream(Console.OpenStandardInput());
		private static ostream cout = new ostream(Console.OpenStandardOutput());
		private static ostream cerr = new ostream(Console.OpenStandardError());
		private static ostream clog = new ostream(Console.OpenStandardError(), true);

		public static int Main()
		{
			try
			{
				int returnValue = solution();
				cout.Flush();
				cerr.Flush();
				return returnValue;
			}
			catch (Exception e)
			{
				Console.WriteLine(e.ToString());
				return -1;
			}
		}
	}
}

namespace Libraries.IO
{
	public class istream : IDisposable
	{
		private BufferedStream buffer;
		private StreamReader reader;
		private Queue<string> words = new Queue<string>();
		private void getWords()
		{
			while (words.Count == 0)
			{
				string [] temp = reader.ReadLine().Split();
				foreach (var str in temp)
				{
					if (str.Length == 0) continue;
					words.Enqueue(str);
				}
			}
		}
		public istream(Stream istr)
		{
			buffer = new BufferedStream(istr);
			reader = new StreamReader(buffer);
		}
		public int Peek()
		{
			return reader.Peek();
		}
		public int Read()
		{
			return reader.Read();
		}
		public string ReadLine()
		{
			return reader.ReadLine();
		}
		public int [] ReadInt32Array()
		{
			return reader.ReadLine().Split().Select(x => Convert.ToInt32(x)).ToArray();
		}
		public long [] ReadInt64Array()
		{
			return reader.ReadLine().Split().Select(x => Convert.ToInt64(x)).ToArray();
		}
		public string [] ReadStringArray()
		{
			return reader.ReadLine().Split();
		}
		public int ReadInt32()
		{
			getWords();
			return Convert.ToInt32(words.Dequeue());
		}
		public long ReadInt64()
		{
			getWords();
			return Convert.ToInt64(words.Dequeue());
		}
		public string ReadString()
		{
			getWords();
			return words.Dequeue();
		}
		public void Dispose()
		{
			reader.Dispose();
			buffer.Dispose();
		}
	}
	public class ostream : IDisposable
	{
		private BufferedStream buffer;
		private StreamWriter writer;
		public ostream(Stream ostr, bool autoflush = false)
		{
			buffer = new BufferedStream(ostr);
			writer = new StreamWriter(buffer);
			writer.AutoFlush = autoflush;
		}
		public void Write(string format, params object[] args)
		{
			writer.Write(format, args);
		}
		public void Write<T>(T value)
		{
			writer.Write(value);
		}
		public void Write<T>(T [] arr, string sep)
		{
			string fmt = "{0}" + sep;
			foreach (var x in arr) writer.Write(fmt, x);
		}
		public void WriteLine(string format, params object[] args)
		{
			writer.WriteLine(format, args);
		}
		public void WriteLine<T>(T value)
		{
			writer.WriteLine(value);
		}
		public void WriteLine<T>(IEnumerable<T> arr, string sep)
		{
			string fmt = "{0}" + sep;
			foreach (var x in arr) writer.Write(fmt, x);
			writer.WriteLine();
		}
		public void WriteLine<T>(IEnumerable<T> arr, string sep, Func<T, T> funct)
		{
			string fmt = "{0}" + sep;
			foreach (var x in arr) writer.Write(fmt, funct(x));
			writer.WriteLine();
		}
		public void WriteLine()
		{
			writer.WriteLine();
		}
		public void Flush()
		{
			writer.Flush();
		}
		public void Dispose()
		{
			writer.Dispose();
			buffer.Dispose();
		}
	}
}
namespace Libraries
{
	public class Utilities
	{
		public static void Swap<T>(ref T x, ref T y)
		{
			T temp = y;
			y = x;
			x = temp;
		}
	}

	public static class Arrays
	{
		private static T Inc<T>(ref T value)
		{
			dynamic temp = value;
			dynamic temp2 = temp;
			value = ++temp2;
			return temp++;
		}
		public static IEnumerable<T> FillDefault<T>(int size) where T : new()
		{
			for (int i = 0; i < size; ++i) yield return new T();
		}
		public static IEnumerable<T> Fill<T>(int size, T value)
		{
			for (int i = 0; i < size; ++i) yield return value;
		}
		public static IEnumerable<T> Iota<T>(int size, T init)
		{
			for (int i = 0; i < size; ++i) yield return Inc(ref init);
		}
		public static T First<T> (this IList<T> container)
		{
			if (container.Count == 0) throw new InvalidOperationException("The container is empty");
			return container[0];
		}
		public static T Last<T> (this IList<T> container)
		{
			if (container.Count == 0) throw new InvalidOperationException("The container is empty");
			return container[container.Count - 1];
		}
		public static void RemoveLast<T> (this IList<T> container)
		{
			if (container.Count == 0) throw new InvalidOperationException("The container is empty");
			container.RemoveAt(container.Count - 1);
		}
	}
}

namespace Libraries.Collections
{
	class PriorityQueue<T> where T : IComparable
	{
	    private List<T> list;
	    public int Count { get { return list.Count; } }
	    public readonly bool IsDescending;

	    public PriorityQueue()
	    {
	        list = new List<T>();
	    }

	    public PriorityQueue(bool isdesc)
	        : this()
	    {
	        IsDescending = isdesc;
	    }

	    public PriorityQueue(int capacity)
	        : this(capacity, false)
	    { }

	    public PriorityQueue(IEnumerable<T> collection)
	        : this(collection, false)
	    { }

	    public PriorityQueue(int capacity, bool isdesc)
	    {
	        list = new List<T>(capacity);
	        IsDescending = isdesc;
	    }

	    public PriorityQueue(IEnumerable<T> collection, bool isdesc)
	        : this()
	    {
	        IsDescending = isdesc;
	        foreach (var item in collection)
	            Enqueue(item);
	    }

	    public void Enqueue(T x)
	    {
	        list.Add(x);
	        int i = Count - 1;

	        while (i > 0)
	        {
	            int p = (i - 1) / 2;
	            if ((IsDescending ? -1 : 1) * list[p].CompareTo(x) <= 0) break;

	            list[i] = list[p];
	            i = p;
	        }

	        if (Count > 0) list[i] = x;
	    }

	    public T Dequeue()
	    {
	        T target = Peek();
	        T root = list[Count - 1];
	        list.RemoveAt(Count - 1);

	        int i = 0;
	        while (i * 2 + 1 < Count)
	        {
	            int a = i * 2 + 1;
	            int b = i * 2 + 2;
	            int c = b < Count && (IsDescending ? -1 : 1) * list[b].CompareTo(list[a]) < 0 ? b : a;

	            if ((IsDescending ? -1 : 1) * list[c].CompareTo(root) >= 0) break;
	            list[i] = list[c];
	            i = c;
	        }

	        if (Count > 0) list[i] = root;
	        return target;
	    }

	    public T Peek()
	    {
	        if (Count == 0) throw new InvalidOperationException("Queue is empty.");
	        return list[0];
	    }

	    public void Clear()
	    {
	        list.Clear();
	    }
	}
    internal class DequeUtility
    {
        public static int ClosestPowerOfTwoGreaterThan(int x)
        {
            x--;
            x |= (x >> 1);
            x |= (x >> 2);
            x |= (x >> 4);
            x |= (x >> 8);
            x |= (x >> 16);
            return (x+1);
        }

        public static int Count<TSource>(IEnumerable<TSource> source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            ICollection<TSource> genericCollection = source as ICollection<TSource>;
            if (genericCollection != null)
            {
                return genericCollection.Count;
            }

            ICollection nonGenericCollection = source as ICollection;
            if (nonGenericCollection != null)
            {
                return nonGenericCollection.Count;
            }

            checked
            {
                int count = 0;
                using (var iterator = source.GetEnumerator())
                {
                    while (iterator.MoveNext())
                    {
                        count++;
                    }
                }
                return count;
            }
        }
    }

    public class Deque<T> : IList<T>
    {
        private const int defaultCapacity = 16;

        private int startOffset;

        private T[] buffer;

        public Deque() : this(defaultCapacity) { }

        public Deque(int capacity)
        {
            if (capacity < 0)
            {
                throw new ArgumentOutOfRangeException(
                    "capacity", "capacity is less than 0.");
            }

            this.Capacity = capacity;
        }

        public Deque(IEnumerable<T> collection)
            : this(DequeUtility.Count(collection))
        {
            InsertRange(0, collection);
        }

        private int capacityClosestPowerOfTwoMinusOne;

        public int Capacity
        {
            get
            {
                return buffer.Length;
            }

            set
            {
                if (value < 0)
                {
                    throw new ArgumentOutOfRangeException(
                        "value",
                        "Capacity is less than 0.");
                }
                else if (value < this.Count)
                {
                    throw new InvalidOperationException(
                        "Capacity cannot be set to a value less than Count");
                }
                else if (null != buffer && value == buffer.Length)
                {
                    return;
                }

                int powOfTwo = DequeUtility.ClosestPowerOfTwoGreaterThan(value);

                value = powOfTwo;

                T[] newBuffer = new T[value];
                this.CopyTo(newBuffer, 0);

                buffer = newBuffer;
                startOffset = 0;
                this.capacityClosestPowerOfTwoMinusOne = powOfTwo - 1;
            }
        }

        public bool IsFull
        {
            get { return this.Count == this.Capacity; }
        }

        public bool IsEmpty
        {
            get { return 0 == this.Count; }
        }

        private void ensureCapacityFor(int numElements)
        {
            if (this.Count + numElements > this.Capacity)
            {
                this.Capacity = this.Count + numElements;
            }
        }

        private int toBufferIndex(int index)
        {
            int bufferIndex;

            bufferIndex = (index + this.startOffset)
                & this.capacityClosestPowerOfTwoMinusOne;

            return bufferIndex;
        }

        private void checkIndexOutOfRange(int index)
        {
            if (index >= this.Count)
            {
                throw new IndexOutOfRangeException(
                    "The supplied index is greater than the Count");
            }
        }

        private static void checkArgumentsOutOfRange(
            int length,
            int offset,
            int count)
        {
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException(
                    "offset", "Invalid offset " + offset);
            }

            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(
                    "count", "Invalid count " + count);
            }

            if (length - offset < count)
            {
                throw new ArgumentException(
                    String.Format(
                    "Invalid offset ({0}) or count + ({1}) "
                    + "for source length {2}",
                    offset, count, length));
            }
        }

        private int shiftStartOffset(int value)
        {
            this.startOffset = toBufferIndex(value);

            return this.startOffset;
        }

        private int preShiftStartOffset(int value)
        {
            int offset = this.startOffset;
            this.shiftStartOffset(value);
            return offset;
        }

        private int postShiftStartOffset(int value)
        {
            return shiftStartOffset(value);
        }

        #region IEnumerable

        public IEnumerator<T> GetEnumerator()
        {
            if (this.startOffset + this.Count > this.Capacity)
            {
                for (int i = this.startOffset; i < this.Capacity; i++)
                {
                    yield return buffer[i];
                }

                int endIndex = toBufferIndex(this.Count);
                for (int i = 0; i < endIndex; i++)
                {
                    yield return buffer[i];
                }
            }
            else
            {
                int endIndex = this.startOffset + this.Count;
                for (int i = this.startOffset; i < endIndex; i++)
                {
                    yield return buffer[i];
                }
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
        #endregion

        #region ICollection

        bool ICollection<T>.IsReadOnly
        {
            get { return false; }
        }

        public int Count
        {
            get;
            private set;
        }

        private void incrementCount(int value)
        {
            this.Count = this.Count + value;
        }

        private void decrementCount(int value)
        {
            this.Count = Math.Max(this.Count - value, 0);
        }

        public void Add(T item)
        {
            AddLast(item);
        }

        private void ClearBuffer(int logicalIndex, int length)
        {
            int offset = toBufferIndex(logicalIndex);
            if (offset + length > this.Capacity)
            {
                int len = this.Capacity - offset;
                Array.Clear(this.buffer, offset, len);

                len = toBufferIndex(logicalIndex + length);
                Array.Clear(this.buffer, 0, len);
            }
            else
            {
                Array.Clear(this.buffer, offset, length);
            }
        }

        public void Clear()
        {
            if (this.Count > 0)
            {
                ClearBuffer(0, this.Count);
            }
            this.Count = 0;
            this.startOffset = 0;
        }

        public bool Contains(T item)
        {
            return this.IndexOf(item) != -1;
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            if (null == array)
            {
                throw new ArgumentNullException("array", "Array is null");
            }

            if (null == this.buffer)
            {
                return;
            }

            checkArgumentsOutOfRange(array.Length, arrayIndex, this.Count);

            if (0 != this.startOffset
                && this.startOffset + this.Count >= this.Capacity)
            {
                int lengthFromStart = this.Capacity - this.startOffset;
                int lengthFromEnd = this.Count - lengthFromStart;

                Array.Copy(
                    buffer, this.startOffset, array, 0, lengthFromStart);

                Array.Copy(
                    buffer, 0, array, lengthFromStart, lengthFromEnd);
            }
            else
            {
                Array.Copy(
                    buffer, this.startOffset, array, 0, Count);
            }
        }

        public bool Remove(T item)
        {
            bool result = true;
            int index = IndexOf(item);

            if (-1 == index)
            {
                result = false;
            }
            else
            {
                RemoveAt(index);
            }

            return result;
        }

        #endregion

        #region List<T>

        public T this[int index]
        {
            get
            {
                return this.Get(index);
            }

            set
            {
                this.Set(index, value);
            }
        }

        public void Insert(int index, T item)
        {
            ensureCapacityFor(1);

            if (index == 0)
            {
                AddFirst(item);
                return;
            }
            else if (index == Count)
            {
                AddLast(item);
                return;
            }

            InsertRange(index, new[] { item });
        }

        public int IndexOf(T item)
        {
            int index = 0;
            foreach (var myItem in this)
            {
                if (myItem.Equals(item))
                {
                    break;
                }
                ++index;
            }

            if (index == this.Count)
            {
                index = -1;
            }

            return index;
        }

        public void RemoveAt(int index)
        {
            if (index == 0)
            {
                RemoveFirst();
                return;
            }
            else if (index == Count - 1)
            {
                RemoveLast();
                return;
            }

            RemoveRange(index, 1);
        }
        #endregion

        public void AddFirst(T item)
        {
            ensureCapacityFor(1);
            buffer[postShiftStartOffset(-1)] = item;
            incrementCount(1);
        }

        public void AddLast(T item)
        {
            ensureCapacityFor(1);
            buffer[toBufferIndex(this.Count)] = item;
            incrementCount(1);
        }

        public T RemoveFirst()
        {
            if (this.IsEmpty)
            {
                throw new InvalidOperationException("The Deque is empty");
            }

            T result = buffer[this.startOffset];
            buffer[preShiftStartOffset(1)] = default(T);
            decrementCount(1);
            return result;
        }

        public T RemoveLast()
        {
            if (this.IsEmpty)
            {
                throw new InvalidOperationException("The Deque is empty");
            }

            decrementCount(1);
            int endIndex = toBufferIndex(this.Count);
            T result = buffer[endIndex];
            buffer[endIndex] = default(T);

            return result;
        }

        public void AddRange(IEnumerable<T> collection)
        {
            AddLastRange(collection);
        }

        public void AddFirstRange(IEnumerable<T> collection)
        {
            AddFirstRange(collection, 0, DequeUtility.Count(collection));
        }

        public void AddFirstRange(
            IEnumerable<T> collection,
            int fromIndex,
            int count)
        {
            InsertRange(0, collection, fromIndex, count);
        }

        public void AddLastRange(IEnumerable<T> collection)
        {
            AddLastRange(collection, 0, DequeUtility.Count(collection));
        }

        public void AddLastRange(
            IEnumerable<T> collection,
            int fromIndex,
            int count)
        {
            InsertRange(this.Count, collection, fromIndex, count);
        }

        public void InsertRange(int index, IEnumerable<T> collection)
        {
            int count = DequeUtility.Count(collection);
            this.InsertRange(index, collection, 0, count);
        }

        public void InsertRange(
            int index,
            IEnumerable<T> collection,
            int fromIndex,
            int count)
        {
            checkIndexOutOfRange(index - 1);

            if (0 == count)
            {
                return;
            }

            ensureCapacityFor(count);

            if (index < this.Count / 2)
            {
                if (index > 0)
                {
                    int copyCount = index;
                    int shiftIndex = this.Capacity - count;
                    for (int j = 0; j < copyCount; j++)
                    {
                        buffer[toBufferIndex(shiftIndex + j)] =
                            buffer[toBufferIndex(j)];
                    }
                }

                this.shiftStartOffset(-count);

            }
            else
            {
                if (index < this.Count)
                {
                    int copyCount = this.Count - index;
                    int shiftIndex = index + count;
                    for (int j = 0; j < copyCount; j++)
                    {
                        buffer[toBufferIndex(shiftIndex + j)] =
                            buffer[toBufferIndex(index + j)];
                    }
                }
            }

            int i = index;
            foreach (T item in collection)
            {
                buffer[toBufferIndex(i)] = item;
                ++i;
            }

            incrementCount(count);
        }

        public void RemoveRange(int index, int count)
        {
            if (this.IsEmpty)
            {
                throw new InvalidOperationException("The Deque is empty");
            }
            if (index > Count - count)
            {
                throw new IndexOutOfRangeException(
                    "The supplied index is greater than the Count");
            }

            ClearBuffer(index, count);

            if (index == 0)
            {
                this.shiftStartOffset(count);
                this.Count -= count;
                return;
            }
            else if (index == Count - count)
            {
                this.Count -= count;
                return;
            }

            if ((index + (count / 2)) < Count / 2)
            {
                int copyCount = index;
                int writeIndex = count;
                for (int j = 0; j < copyCount; j++)
                {
                    buffer[toBufferIndex(writeIndex + j)]
                        = buffer[toBufferIndex(j)];
                }

                this.shiftStartOffset(count);
            }
            else
            {
                int copyCount = Count - count - index;
                int readIndex = index + count;
                for (int j = 0; j < copyCount; ++j)
                {
                    buffer[toBufferIndex(index + j)] =
                        buffer[toBufferIndex(readIndex + j)];
                }
            }

            decrementCount(count);
        }
        public T Get(int index)
        {
            checkIndexOutOfRange(index);
            return buffer[toBufferIndex(index)];
        }

        public void Set(int index, T item)
        {
            checkIndexOutOfRange(index);
            buffer[toBufferIndex(index)] = item;
        }

    }
}


//Template by _Trung_Nguyen
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections;
using System.IO;

using Libraries;
using Libraries.IO;
using Libraries.Collections;

namespace Codeforces
{
	public class sample
	{
		private static int solution()
		{
			int n = cin.ReadInt32();

			int [] f = cin.ReadInt32Array();
			for (int i = 0; i < n; ++i) --f[i];

			int [] from = Arrays.Fill(n, -1).ToArray();

			for (int i = 0; i < n; ++i) from[f[i]] = i;

			bool [] visited = new bool[n];

			List<int> start = new List<int>();
			List<int> end = new List<int>();

			int weakComponents = 0;
			int strongComponents = 0;

			for (int i = 0; i < n; ++i)
			{
				if (from[i] != -1) continue;
				if (visited[i]) continue;

				++weakComponents;

				start.Add(i);

				int current = i;
				while (!visited[f[current]])
				{
					visited[current] = true;
					current = f[current];
				}

				visited[current] = true;

				end.Add(current);
			}

			for (int i = 0; i < n; ++i)
			{
				if (visited[i]) continue;

				++strongComponents;

				start.Add(i);
				end.Add(i);

				int current = i;
				while (!visited[f[current]])
				{
					visited[current] = true;
					current = f[current];
				}

				visited[current] = true;
			}

			if ((weakComponents == 0) && (strongComponents == 1))
			{
				cout.Write("0");
				return 0;
			}

			int k = start.Count;
			cout.WriteLine(k);

			for (int i = 0; i < k; ++i)
			{
				cout.WriteLine("{0} {1}", end[i] + 1, start[(i + 1) % k] + 1);
			}

			return 0;
		}

//===============Prewritten code======================
		private static istream cin = new istream(Console.OpenStandardInput());
		private static ostream cout = new ostream(Console.OpenStandardOutput());
		private static ostream cerr = new ostream(Console.OpenStandardError());
		private static ostream clog = new ostream(Console.OpenStandardError(), true);

		public static int Main()
		{
			try
			{
				int returnValue = solution();
				cout.Flush();
				cerr.Flush();
				return returnValue;
			}
			catch (Exception e)
			{
				Console.WriteLine(e.ToString());
				return -1;
			}
		}
	}
}

namespace Libraries.IO
{
	public class istream : IDisposable
	{
		private BufferedStream buffer;
		private StreamReader reader;
		private Queue<string> words = new Queue<string>();
		private void getWords()
		{
			while (words.Count == 0)
			{
				string [] temp = reader.ReadLine().Split();
				foreach (var str in temp)
				{
					if (str.Length == 0) continue;
					words.Enqueue(str);
				}
			}
		}
		public istream(Stream istr)
		{
			buffer = new BufferedStream(istr);
			reader = new StreamReader(buffer);
		}
		public int Peek()
		{
			return reader.Peek();
		}
		public int Read()
		{
			return reader.Read();
		}
		public string ReadLine()
		{
			return reader.ReadLine();
		}
		public int [] ReadInt32Array()
		{
			return reader.ReadLine().Split().Select(x => Convert.ToInt32(x)).ToArray();
		}
		public long [] ReadInt64Array()
		{
			return reader.ReadLine().Split().Select(x => Convert.ToInt64(x)).ToArray();
		}
		public string [] ReadStringArray()
		{
			return reader.ReadLine().Split();
		}
		public int ReadInt32()
		{
			getWords();
			return Convert.ToInt32(words.Dequeue());
		}
		public long ReadInt64()
		{
			getWords();
			return Convert.ToInt64(words.Dequeue());
		}
		public string ReadString()
		{
			getWords();
			return words.Dequeue();
		}
		public void Dispose()
		{
			reader.Dispose();
			buffer.Dispose();
		}
	}
	public class ostream : IDisposable
	{
		private BufferedStream buffer;
		private StreamWriter writer;
		public ostream(Stream ostr, bool autoflush = false)
		{
			buffer = new BufferedStream(ostr);
			writer = new StreamWriter(buffer);
			writer.AutoFlush = autoflush;
		}
		public void Write(string format, params object[] args)
		{
			writer.Write(format, args);
		}
		public void Write<T>(T value)
		{
			writer.Write(value);
		}
		public void Write<T>(T [] arr, string sep)
		{
			string fmt = "{0}" + sep;
			foreach (var x in arr) writer.Write(fmt, x);
		}
		public void WriteLine(string format, params object[] args)
		{
			writer.WriteLine(format, args);
		}
		public void WriteLine<T>(T value)
		{
			writer.WriteLine(value);
		}
		public void WriteLine<T>(IEnumerable<T> arr, string sep)
		{
			string fmt = "{0}" + sep;
			foreach (var x in arr) writer.Write(fmt, x);
			writer.WriteLine();
		}
		public void WriteLine<T>(IEnumerable<T> arr, string sep, Func<T, T> funct)
		{
			string fmt = "{0}" + sep;
			foreach (var x in arr) writer.Write(fmt, funct(x));
			writer.WriteLine();
		}
		public void WriteLine()
		{
			writer.WriteLine();
		}
		public void Flush()
		{
			writer.Flush();
		}
		public void Dispose()
		{
			writer.Dispose();
			buffer.Dispose();
		}
	}
}
namespace Libraries
{
	public class Utilities
	{
		public static void Swap<T>(ref T x, ref T y)
		{
			T temp = y;
			y = x;
			x = temp;
		}
	}

	public static class Arrays
	{
		private static T Inc<T>(ref T value)
		{
			dynamic temp = value;
			dynamic temp2 = temp;
			value = ++temp2;
			return temp++;
		}
		public static IEnumerable<T> FillDefault<T>(int size) where T : new()
		{
			for (int i = 0; i < size; ++i) yield return new T();
		}
		public static IEnumerable<T> Fill<T>(int size, T value)
		{
			for (int i = 0; i < size; ++i) yield return value;
		}
		public static IEnumerable<T> Iota<T>(int size, T init)
		{
			for (int i = 0; i < size; ++i) yield return Inc(ref init);
		}
		public static T First<T> (this IList<T> container)
		{
			if (container.Count == 0) throw new InvalidOperationException("The container is empty");
			return container[0];
		}
		public static T Last<T> (this IList<T> container)
		{
			if (container.Count == 0) throw new InvalidOperationException("The container is empty");
			return container[container.Count - 1];
		}
		public static void RemoveLast<T> (this IList<T> container)
		{
			if (container.Count == 0) throw new InvalidOperationException("The container is empty");
			container.RemoveAt(container.Count - 1);
		}
	}
}

namespace Libraries.Collections
{
	class PriorityQueue<T> where T : IComparable
	{
	    private List<T> list;
	    public int Count { get { return list.Count; } }
	    public readonly bool IsDescending;

	    public PriorityQueue()
	    {
	        list = new List<T>();
	    }

	    public PriorityQueue(bool isdesc)
	        : this()
	    {
	        IsDescending = isdesc;
	    }

	    public PriorityQueue(int capacity)
	        : this(capacity, false)
	    { }

	    public PriorityQueue(IEnumerable<T> collection)
	        : this(collection, false)
	    { }

	    public PriorityQueue(int capacity, bool isdesc)
	    {
	        list = new List<T>(capacity);
	        IsDescending = isdesc;
	    }

	    public PriorityQueue(IEnumerable<T> collection, bool isdesc)
	        : this()
	    {
	        IsDescending = isdesc;
	        foreach (var item in collection)
	            Enqueue(item);
	    }

	    public void Enqueue(T x)
	    {
	        list.Add(x);
	        int i = Count - 1;

	        while (i > 0)
	        {
	            int p = (i - 1) / 2;
	            if ((IsDescending ? -1 : 1) * list[p].CompareTo(x) <= 0) break;

	            list[i] = list[p];
	            i = p;
	        }

	        if (Count > 0) list[i] = x;
	    }

	    public T Dequeue()
	    {
	        T target = Peek();
	        T root = list[Count - 1];
	        list.RemoveAt(Count - 1);

	        int i = 0;
	        while (i * 2 + 1 < Count)
	        {
	            int a = i * 2 + 1;
	            int b = i * 2 + 2;
	            int c = b < Count && (IsDescending ? -1 : 1) * list[b].CompareTo(list[a]) < 0 ? b : a;

	            if ((IsDescending ? -1 : 1) * list[c].CompareTo(root) >= 0) break;
	            list[i] = list[c];
	            i = c;
	        }

	        if (Count > 0) list[i] = root;
	        return target;
	    }

	    public T Peek()
	    {
	        if (Count == 0) throw new InvalidOperationException("Queue is empty.");
	        return list[0];
	    }

	    public void Clear()
	    {
	        list.Clear();
	    }
	}
    internal class DequeUtility
    {
        public static int ClosestPowerOfTwoGreaterThan(int x)
        {
            x--;
            x |= (x >> 1);
            x |= (x >> 2);
            x |= (x >> 4);
            x |= (x >> 8);
            x |= (x >> 16);
            return (x+1);
        }

        public static int Count<TSource>(IEnumerable<TSource> source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            ICollection<TSource> genericCollection = source as ICollection<TSource>;
            if (genericCollection != null)
            {
                return genericCollection.Count;
            }

            ICollection nonGenericCollection = source as ICollection;
            if (nonGenericCollection != null)
            {
                return nonGenericCollection.Count;
            }

            checked
            {
                int count = 0;
                using (var iterator = source.GetEnumerator())
                {
                    while (iterator.MoveNext())
                    {
                        count++;
                    }
                }
                return count;
            }
        }
    }

    public class Deque<T> : IList<T>
    {
        private const int defaultCapacity = 16;

        private int startOffset;

        private T[] buffer;

        public Deque() : this(defaultCapacity) { }

        public Deque(int capacity)
        {
            if (capacity < 0)
            {
                throw new ArgumentOutOfRangeException(
                    "capacity", "capacity is less than 0.");
            }

            this.Capacity = capacity;
        }

        public Deque(IEnumerable<T> collection)
            : this(DequeUtility.Count(collection))
        {
            InsertRange(0, collection);
        }

        private int capacityClosestPowerOfTwoMinusOne;

        public int Capacity
        {
            get
            {
                return buffer.Length;
            }

            set
            {
                if (value < 0)
                {
                    throw new ArgumentOutOfRangeException(
                        "value",
                        "Capacity is less than 0.");
                }
                else if (value < this.Count)
                {
                    throw new InvalidOperationException(
                        "Capacity cannot be set to a value less than Count");
                }
                else if (null != buffer && value == buffer.Length)
                {
                    return;
                }

                int powOfTwo = DequeUtility.ClosestPowerOfTwoGreaterThan(value);

                value = powOfTwo;

                T[] newBuffer = new T[value];
                this.CopyTo(newBuffer, 0);

                buffer = newBuffer;
                startOffset = 0;
                this.capacityClosestPowerOfTwoMinusOne = powOfTwo - 1;
            }
        }

        public bool IsFull
        {
            get { return this.Count == this.Capacity; }
        }

        public bool IsEmpty
        {
            get { return 0 == this.Count; }
        }

        private void ensureCapacityFor(int numElements)
        {
            if (this.Count + numElements > this.Capacity)
            {
                this.Capacity = this.Count + numElements;
            }
        }

        private int toBufferIndex(int index)
        {
            int bufferIndex;

            bufferIndex = (index + this.startOffset)
                & this.capacityClosestPowerOfTwoMinusOne;

            return bufferIndex;
        }

        private void checkIndexOutOfRange(int index)
        {
            if (index >= this.Count)
            {
                throw new IndexOutOfRangeException(
                    "The supplied index is greater than the Count");
            }
        }

        private static void checkArgumentsOutOfRange(
            int length,
            int offset,
            int count)
        {
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException(
                    "offset", "Invalid offset " + offset);
            }

            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(
                    "count", "Invalid count " + count);
            }

            if (length - offset < count)
            {
                throw new ArgumentException(
                    String.Format(
                    "Invalid offset ({0}) or count + ({1}) "
                    + "for source length {2}",
                    offset, count, length));
            }
        }

        private int shiftStartOffset(int value)
        {
            this.startOffset = toBufferIndex(value);

            return this.startOffset;
        }

        private int preShiftStartOffset(int value)
        {
            int offset = this.startOffset;
            this.shiftStartOffset(value);
            return offset;
        }

        private int postShiftStartOffset(int value)
        {
            return shiftStartOffset(value);
        }

        #region IEnumerable

        public IEnumerator<T> GetEnumerator()
        {
            if (this.startOffset + this.Count > this.Capacity)
            {
                for (int i = this.startOffset; i < this.Capacity; i++)
                {
                    yield return buffer[i];
                }

                int endIndex = toBufferIndex(this.Count);
                for (int i = 0; i < endIndex; i++)
                {
                    yield return buffer[i];
                }
            }
            else
            {
                int endIndex = this.startOffset + this.Count;
                for (int i = this.startOffset; i < endIndex; i++)
                {
                    yield return buffer[i];
                }
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
        #endregion

        #region ICollection

        bool ICollection<T>.IsReadOnly
        {
            get { return false; }
        }

        public int Count
        {
            get;
            private set;
        }

        private void incrementCount(int value)
        {
            this.Count = this.Count + value;
        }

        private void decrementCount(int value)
        {
            this.Count = Math.Max(this.Count - value, 0);
        }

        public void Add(T item)
        {
            AddLast(item);
        }

        private void ClearBuffer(int logicalIndex, int length)
        {
            int offset = toBufferIndex(logicalIndex);
            if (offset + length > this.Capacity)
            {
                int len = this.Capacity - offset;
                Array.Clear(this.buffer, offset, len);

                len = toBufferIndex(logicalIndex + length);
                Array.Clear(this.buffer, 0, len);
            }
            else
            {
                Array.Clear(this.buffer, offset, length);
            }
        }

        public void Clear()
        {
            if (this.Count > 0)
            {
                ClearBuffer(0, this.Count);
            }
            this.Count = 0;
            this.startOffset = 0;
        }

        public bool Contains(T item)
        {
            return this.IndexOf(item) != -1;
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            if (null == array)
            {
                throw new ArgumentNullException("array", "Array is null");
            }

            if (null == this.buffer)
            {
                return;
            }

            checkArgumentsOutOfRange(array.Length, arrayIndex, this.Count);

            if (0 != this.startOffset
                && this.startOffset + this.Count >= this.Capacity)
            {
                int lengthFromStart = this.Capacity - this.startOffset;
                int lengthFromEnd = this.Count - lengthFromStart;

                Array.Copy(
                    buffer, this.startOffset, array, 0, lengthFromStart);

                Array.Copy(
                    buffer, 0, array, lengthFromStart, lengthFromEnd);
            }
            else
            {
                Array.Copy(
                    buffer, this.startOffset, array, 0, Count);
            }
        }

        public bool Remove(T item)
        {
            bool result = true;
            int index = IndexOf(item);

            if (-1 == index)
            {
                result = false;
            }
            else
            {
                RemoveAt(index);
            }

            return result;
        }

        #endregion

        #region List<T>

        public T this[int index]
        {
            get
            {
                return this.Get(index);
            }

            set
            {
                this.Set(index, value);
            }
        }

        public void Insert(int index, T item)
        {
            ensureCapacityFor(1);

            if (index == 0)
            {
                AddFirst(item);
                return;
            }
            else if (index == Count)
            {
                AddLast(item);
                return;
            }

            InsertRange(index, new[] { item });
        }

        public int IndexOf(T item)
        {
            int index = 0;
            foreach (var myItem in this)
            {
                if (myItem.Equals(item))
                {
                    break;
                }
                ++index;
            }

            if (index == this.Count)
            {
                index = -1;
            }

            return index;
        }

        public void RemoveAt(int index)
        {
            if (index == 0)
            {
                RemoveFirst();
                return;
            }
            else if (index == Count - 1)
            {
                RemoveLast();
                return;
            }

            RemoveRange(index, 1);
        }
        #endregion

        public void AddFirst(T item)
        {
            ensureCapacityFor(1);
            buffer[postShiftStartOffset(-1)] = item;
            incrementCount(1);
        }

        public void AddLast(T item)
        {
            ensureCapacityFor(1);
            buffer[toBufferIndex(this.Count)] = item;
            incrementCount(1);
        }

        public T RemoveFirst()
        {
            if (this.IsEmpty)
            {
                throw new InvalidOperationException("The Deque is empty");
            }

            T result = buffer[this.startOffset];
            buffer[preShiftStartOffset(1)] = default(T);
            decrementCount(1);
            return result;
        }

        public T RemoveLast()
        {
            if (this.IsEmpty)
            {
                throw new InvalidOperationException("The Deque is empty");
            }

            decrementCount(1);
            int endIndex = toBufferIndex(this.Count);
            T result = buffer[endIndex];
            buffer[endIndex] = default(T);

            return result;
        }

        public void AddRange(IEnumerable<T> collection)
        {
            AddLastRange(collection);
        }

        public void AddFirstRange(IEnumerable<T> collection)
        {
            AddFirstRange(collection, 0, DequeUtility.Count(collection));
        }

        public void AddFirstRange(
            IEnumerable<T> collection,
            int fromIndex,
            int count)
        {
            InsertRange(0, collection, fromIndex, count);
        }

        public void AddLastRange(IEnumerable<T> collection)
        {
            AddLastRange(collection, 0, DequeUtility.Count(collection));
        }

        public void AddLastRange(
            IEnumerable<T> collection,
            int fromIndex,
            int count)
        {
            InsertRange(this.Count, collection, fromIndex, count);
        }

        public void InsertRange(int index, IEnumerable<T> collection)
        {
            int count = DequeUtility.Count(collection);
            this.InsertRange(index, collection, 0, count);
        }

        public void InsertRange(
            int index,
            IEnumerable<T> collection,
            int fromIndex,
            int count)
        {
            checkIndexOutOfRange(index - 1);

            if (0 == count)
            {
                return;
            }

            ensureCapacityFor(count);

            if (index < this.Count / 2)
            {
                if (index > 0)
                {
                    int copyCount = index;
                    int shiftIndex = this.Capacity - count;
                    for (int j = 0; j < copyCount; j++)
                    {
                        buffer[toBufferIndex(shiftIndex + j)] =
                            buffer[toBufferIndex(j)];
                    }
                }

                this.shiftStartOffset(-count);

            }
            else
            {
                if (index < this.Count)
                {
                    int copyCount = this.Count - index;
                    int shiftIndex = index + count;
                    for (int j = 0; j < copyCount; j++)
                    {
                        buffer[toBufferIndex(shiftIndex + j)] =
                            buffer[toBufferIndex(index + j)];
                    }
                }
            }

            int i = index;
            foreach (T item in collection)
            {
                buffer[toBufferIndex(i)] = item;
                ++i;
            }

            incrementCount(count);
        }

        public void RemoveRange(int index, int count)
        {
            if (this.IsEmpty)
            {
                throw new InvalidOperationException("The Deque is empty");
            }
            if (index > Count - count)
            {
                throw new IndexOutOfRangeException(
                    "The supplied index is greater than the Count");
            }

            ClearBuffer(index, count);

            if (index == 0)
            {
                this.shiftStartOffset(count);
                this.Count -= count;
                return;
            }
            else if (index == Count - count)
            {
                this.Count -= count;
                return;
            }

            if ((index + (count / 2)) < Count / 2)
            {
                int copyCount = index;
                int writeIndex = count;
                for (int j = 0; j < copyCount; j++)
                {
                    buffer[toBufferIndex(writeIndex + j)]
                        = buffer[toBufferIndex(j)];
                }

                this.shiftStartOffset(count);
            }
            else
            {
                int copyCount = Count - count - index;
                int readIndex = index + count;
                for (int j = 0; j < copyCount; ++j)
                {
                    buffer[toBufferIndex(index + j)] =
                        buffer[toBufferIndex(readIndex + j)];
                }
            }

            decrementCount(count);
        }
        public T Get(int index)
        {
            checkIndexOutOfRange(index);
            return buffer[toBufferIndex(index)];
        }

        public void Set(int index, T item)
        {
            checkIndexOutOfRange(index);
            buffer[toBufferIndex(index)] = item;
        }

    }
}


//Template by _Trung_Nguyen
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections;
using System.IO;

using Libraries;
using Libraries.IO;
using Libraries.Collections;

namespace Codeforces
{
	public class sample
	{
		private static int solution()
		{
			int n = cin.ReadInt32();

			int [] f = cin.ReadInt32Array();
			for (int i = 0; i < n; ++i) --f[i];

			int [] from = Arrays.Fill(n, -1).ToArray();

			for (int i = 0; i < n; ++i) from[f[i]] = i;

			bool [] visited = new bool[n];

			List<int> start = new List<int>();
			List<int> end = new List<int>();

			for (int i = 0; i < n; ++i)
			{
				if (from[i] != -1) continue;
				if (visited[i]) continue;

				start.Add(i);
				visited[i] = true;

				int current = f[i];
				while (!visited[current])
				{
					visited[current] = true;
					current = f[current];
				}

				end.Add(current);
			}

			int k = start.Count;
			cout.WriteLine(k);

//			clog.WriteLine("ok here");

			for (int i = 0; i < k; ++i)
			{
				cout.WriteLine("{0} {1}", end[i] + 1, start[(i + 1) % k] + 1);
			}

			return 0;
		}

//===============Prewritten code======================
		private static istream cin = new istream(Console.OpenStandardInput());
		private static ostream cout = new ostream(Console.OpenStandardOutput());
		private static ostream cerr = new ostream(Console.OpenStandardError());
		private static ostream clog = new ostream(Console.OpenStandardError(), true);

		public static int Main()
		{
			try
			{
				int returnValue = solution();
				cout.Flush();
				cerr.Flush();
				return returnValue;
			}
			catch (Exception e)
			{
				Console.WriteLine(e.ToString());
				return -1;
			}
		}
	}
}

namespace Libraries.IO
{
	public class istream : IDisposable
	{
		private BufferedStream buffer;
		private StreamReader reader;
		private Queue<string> words = new Queue<string>();
		private void getWords()
		{
			while (words.Count == 0)
			{
				string [] temp = reader.ReadLine().Split();
				foreach (var str in temp)
				{
					if (str.Length == 0) continue;
					words.Enqueue(str);
				}
			}
		}
		public istream(Stream istr)
		{
			buffer = new BufferedStream(istr);
			reader = new StreamReader(buffer);
		}
		public int Peek()
		{
			return reader.Peek();
		}
		public int Read()
		{
			return reader.Read();
		}
		public string ReadLine()
		{
			return reader.ReadLine();
		}
		public int [] ReadInt32Array()
		{
			return reader.ReadLine().Split().Select(x => Convert.ToInt32(x)).ToArray();
		}
		public long [] ReadInt64Array()
		{
			return reader.ReadLine().Split().Select(x => Convert.ToInt64(x)).ToArray();
		}
		public string [] ReadStringArray()
		{
			return reader.ReadLine().Split();
		}
		public int ReadInt32()
		{
			getWords();
			return Convert.ToInt32(words.Dequeue());
		}
		public long ReadInt64()
		{
			getWords();
			return Convert.ToInt64(words.Dequeue());
		}
		public string ReadString()
		{
			getWords();
			return words.Dequeue();
		}
		public void Dispose()
		{
			reader.Dispose();
			buffer.Dispose();
		}
	}
	public class ostream : IDisposable
	{
		private BufferedStream buffer;
		private StreamWriter writer;
		public ostream(Stream ostr, bool autoflush = false)
		{
			buffer = new BufferedStream(ostr);
			writer = new StreamWriter(buffer);
			writer.AutoFlush = autoflush;
		}
		public void Write(string format, params object[] args)
		{
			writer.Write(format, args);
		}
		public void Write<T>(T value)
		{
			writer.Write(value);
		}
		public void Write<T>(T [] arr, string sep)
		{
			string fmt = "{0}" + sep;
			foreach (var x in arr) writer.Write(fmt, x);
		}
		public void WriteLine(string format, params object[] args)
		{
			writer.WriteLine(format, args);
		}
		public void WriteLine<T>(T value)
		{
			writer.WriteLine(value);
		}
		public void WriteLine<T>(IEnumerable<T> arr, string sep)
		{
			string fmt = "{0}" + sep;
			foreach (var x in arr) writer.Write(fmt, x);
			writer.WriteLine();
		}
		public void WriteLine<T>(IEnumerable<T> arr, string sep, Func<T, T> funct)
		{
			string fmt = "{0}" + sep;
			foreach (var x in arr) writer.Write(fmt, funct(x));
			writer.WriteLine();
		}
		public void WriteLine()
		{
			writer.WriteLine();
		}
		public void Flush()
		{
			writer.Flush();
		}
		public void Dispose()
		{
			writer.Dispose();
			buffer.Dispose();
		}
	}
}
namespace Libraries
{
	public class Utilities
	{
		public static void Swap<T>(ref T x, ref T y)
		{
			T temp = y;
			y = x;
			x = temp;
		}
	}

	public static class Arrays
	{
		private static T Inc<T>(ref T value)
		{
			dynamic temp = value;
			dynamic temp2 = temp;
			value = ++temp2;
			return temp++;
		}
		public static IEnumerable<T> FillDefault<T>(int size) where T : new()
		{
			for (int i = 0; i < size; ++i) yield return new T();
		}
		public static IEnumerable<T> Fill<T>(int size, T value)
		{
			for (int i = 0; i < size; ++i) yield return value;
		}
		public static IEnumerable<T> Iota<T>(int size, T init)
		{
			for (int i = 0; i < size; ++i) yield return Inc(ref init);
		}
		public static T First<T> (this IList<T> container)
		{
			if (container.Count == 0) throw new InvalidOperationException("The container is empty");
			return container[0];
		}
		public static T Last<T> (this IList<T> container)
		{
			if (container.Count == 0) throw new InvalidOperationException("The container is empty");
			return container[container.Count - 1];
		}
		public static void RemoveLast<T> (this IList<T> container)
		{
			if (container.Count == 0) throw new InvalidOperationException("The container is empty");
			container.RemoveAt(container.Count - 1);
		}
	}
}

namespace Libraries.Collections
{
	class PriorityQueue<T> where T : IComparable
	{
	    private List<T> list;
	    public int Count { get { return list.Count; } }
	    public readonly bool IsDescending;

	    public PriorityQueue()
	    {
	        list = new List<T>();
	    }

	    public PriorityQueue(bool isdesc)
	        : this()
	    {
	        IsDescending = isdesc;
	    }

	    public PriorityQueue(int capacity)
	        : this(capacity, false)
	    { }

	    public PriorityQueue(IEnumerable<T> collection)
	        : this(collection, false)
	    { }

	    public PriorityQueue(int capacity, bool isdesc)
	    {
	        list = new List<T>(capacity);
	        IsDescending = isdesc;
	    }

	    public PriorityQueue(IEnumerable<T> collection, bool isdesc)
	        : this()
	    {
	        IsDescending = isdesc;
	        foreach (var item in collection)
	            Enqueue(item);
	    }

	    public void Enqueue(T x)
	    {
	        list.Add(x);
	        int i = Count - 1;

	        while (i > 0)
	        {
	            int p = (i - 1) / 2;
	            if ((IsDescending ? -1 : 1) * list[p].CompareTo(x) <= 0) break;

	            list[i] = list[p];
	            i = p;
	        }

	        if (Count > 0) list[i] = x;
	    }

	    public T Dequeue()
	    {
	        T target = Peek();
	        T root = list[Count - 1];
	        list.RemoveAt(Count - 1);

	        int i = 0;
	        while (i * 2 + 1 < Count)
	        {
	            int a = i * 2 + 1;
	            int b = i * 2 + 2;
	            int c = b < Count && (IsDescending ? -1 : 1) * list[b].CompareTo(list[a]) < 0 ? b : a;

	            if ((IsDescending ? -1 : 1) * list[c].CompareTo(root) >= 0) break;
	            list[i] = list[c];
	            i = c;
	        }

	        if (Count > 0) list[i] = root;
	        return target;
	    }

	    public T Peek()
	    {
	        if (Count == 0) throw new InvalidOperationException("Queue is empty.");
	        return list[0];
	    }

	    public void Clear()
	    {
	        list.Clear();
	    }
	}
    internal class DequeUtility
    {
        public static int ClosestPowerOfTwoGreaterThan(int x)
        {
            x--;
            x |= (x >> 1);
            x |= (x >> 2);
            x |= (x >> 4);
            x |= (x >> 8);
            x |= (x >> 16);
            return (x+1);
        }

        public static int Count<TSource>(IEnumerable<TSource> source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            ICollection<TSource> genericCollection = source as ICollection<TSource>;
            if (genericCollection != null)
            {
                return genericCollection.Count;
            }

            ICollection nonGenericCollection = source as ICollection;
            if (nonGenericCollection != null)
            {
                return nonGenericCollection.Count;
            }

            checked
            {
                int count = 0;
                using (var iterator = source.GetEnumerator())
                {
                    while (iterator.MoveNext())
                    {
                        count++;
                    }
                }
                return count;
            }
        }
    }

    public class Deque<T> : IList<T>
    {
        private const int defaultCapacity = 16;

        private int startOffset;

        private T[] buffer;

        public Deque() : this(defaultCapacity) { }

        public Deque(int capacity)
        {
            if (capacity < 0)
            {
                throw new ArgumentOutOfRangeException(
                    "capacity", "capacity is less than 0.");
            }

            this.Capacity = capacity;
        }

        public Deque(IEnumerable<T> collection)
            : this(DequeUtility.Count(collection))
        {
            InsertRange(0, collection);
        }

        private int capacityClosestPowerOfTwoMinusOne;

        public int Capacity
        {
            get
            {
                return buffer.Length;
            }

            set
            {
                if (value < 0)
                {
                    throw new ArgumentOutOfRangeException(
                        "value",
                        "Capacity is less than 0.");
                }
                else if (value < this.Count)
                {
                    throw new InvalidOperationException(
                        "Capacity cannot be set to a value less than Count");
                }
                else if (null != buffer && value == buffer.Length)
                {
                    return;
                }

                int powOfTwo = DequeUtility.ClosestPowerOfTwoGreaterThan(value);

                value = powOfTwo;

                T[] newBuffer = new T[value];
                this.CopyTo(newBuffer, 0);

                buffer = newBuffer;
                startOffset = 0;
                this.capacityClosestPowerOfTwoMinusOne = powOfTwo - 1;
            }
        }

        public bool IsFull
        {
            get { return this.Count == this.Capacity; }
        }

        public bool IsEmpty
        {
            get { return 0 == this.Count; }
        }

        private void ensureCapacityFor(int numElements)
        {
            if (this.Count + numElements > this.Capacity)
            {
                this.Capacity = this.Count + numElements;
            }
        }

        private int toBufferIndex(int index)
        {
            int bufferIndex;

            bufferIndex = (index + this.startOffset)
                & this.capacityClosestPowerOfTwoMinusOne;

            return bufferIndex;
        }

        private void checkIndexOutOfRange(int index)
        {
            if (index >= this.Count)
            {
                throw new IndexOutOfRangeException(
                    "The supplied index is greater than the Count");
            }
        }

        private static void checkArgumentsOutOfRange(
            int length,
            int offset,
            int count)
        {
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException(
                    "offset", "Invalid offset " + offset);
            }

            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(
                    "count", "Invalid count " + count);
            }

            if (length - offset < count)
            {
                throw new ArgumentException(
                    String.Format(
                    "Invalid offset ({0}) or count + ({1}) "
                    + "for source length {2}",
                    offset, count, length));
            }
        }

        private int shiftStartOffset(int value)
        {
            this.startOffset = toBufferIndex(value);

            return this.startOffset;
        }

        private int preShiftStartOffset(int value)
        {
            int offset = this.startOffset;
            this.shiftStartOffset(value);
            return offset;
        }

        private int postShiftStartOffset(int value)
        {
            return shiftStartOffset(value);
        }

        #region IEnumerable

        public IEnumerator<T> GetEnumerator()
        {
            if (this.startOffset + this.Count > this.Capacity)
            {
                for (int i = this.startOffset; i < this.Capacity; i++)
                {
                    yield return buffer[i];
                }

                int endIndex = toBufferIndex(this.Count);
                for (int i = 0; i < endIndex; i++)
                {
                    yield return buffer[i];
                }
            }
            else
            {
                int endIndex = this.startOffset + this.Count;
                for (int i = this.startOffset; i < endIndex; i++)
                {
                    yield return buffer[i];
                }
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
        #endregion

        #region ICollection

        bool ICollection<T>.IsReadOnly
        {
            get { return false; }
        }

        public int Count
        {
            get;
            private set;
        }

        private void incrementCount(int value)
        {
            this.Count = this.Count + value;
        }

        private void decrementCount(int value)
        {
            this.Count = Math.Max(this.Count - value, 0);
        }

        public void Add(T item)
        {
            AddLast(item);
        }

        private void ClearBuffer(int logicalIndex, int length)
        {
            int offset = toBufferIndex(logicalIndex);
            if (offset + length > this.Capacity)
            {
                int len = this.Capacity - offset;
                Array.Clear(this.buffer, offset, len);

                len = toBufferIndex(logicalIndex + length);
                Array.Clear(this.buffer, 0, len);
            }
            else
            {
                Array.Clear(this.buffer, offset, length);
            }
        }

        public void Clear()
        {
            if (this.Count > 0)
            {
                ClearBuffer(0, this.Count);
            }
            this.Count = 0;
            this.startOffset = 0;
        }

        public bool Contains(T item)
        {
            return this.IndexOf(item) != -1;
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            if (null == array)
            {
                throw new ArgumentNullException("array", "Array is null");
            }

            if (null == this.buffer)
            {
                return;
            }

            checkArgumentsOutOfRange(array.Length, arrayIndex, this.Count);

            if (0 != this.startOffset
                && this.startOffset + this.Count >= this.Capacity)
            {
                int lengthFromStart = this.Capacity - this.startOffset;
                int lengthFromEnd = this.Count - lengthFromStart;

                Array.Copy(
                    buffer, this.startOffset, array, 0, lengthFromStart);

                Array.Copy(
                    buffer, 0, array, lengthFromStart, lengthFromEnd);
            }
            else
            {
                Array.Copy(
                    buffer, this.startOffset, array, 0, Count);
            }
        }

        public bool Remove(T item)
        {
            bool result = true;
            int index = IndexOf(item);

            if (-1 == index)
            {
                result = false;
            }
            else
            {
                RemoveAt(index);
            }

            return result;
        }

        #endregion

        #region List<T>

        public T this[int index]
        {
            get
            {
                return this.Get(index);
            }

            set
            {
                this.Set(index, value);
            }
        }

        public void Insert(int index, T item)
        {
            ensureCapacityFor(1);

            if (index == 0)
            {
                AddFirst(item);
                return;
            }
            else if (index == Count)
            {
                AddLast(item);
                return;
            }

            InsertRange(index, new[] { item });
        }

        public int IndexOf(T item)
        {
            int index = 0;
            foreach (var myItem in this)
            {
                if (myItem.Equals(item))
                {
                    break;
                }
                ++index;
            }

            if (index == this.Count)
            {
                index = -1;
            }

            return index;
        }

        public void RemoveAt(int index)
        {
            if (index == 0)
            {
                RemoveFirst();
                return;
            }
            else if (index == Count - 1)
            {
                RemoveLast();
                return;
            }

            RemoveRange(index, 1);
        }
        #endregion

        public void AddFirst(T item)
        {
            ensureCapacityFor(1);
            buffer[postShiftStartOffset(-1)] = item;
            incrementCount(1);
        }

        public void AddLast(T item)
        {
            ensureCapacityFor(1);
            buffer[toBufferIndex(this.Count)] = item;
            incrementCount(1);
        }

        public T RemoveFirst()
        {
            if (this.IsEmpty)
            {
                throw new InvalidOperationException("The Deque is empty");
            }

            T result = buffer[this.startOffset];
            buffer[preShiftStartOffset(1)] = default(T);
            decrementCount(1);
            return result;
        }

        public T RemoveLast()
        {
            if (this.IsEmpty)
            {
                throw new InvalidOperationException("The Deque is empty");
            }

            decrementCount(1);
            int endIndex = toBufferIndex(this.Count);
            T result = buffer[endIndex];
            buffer[endIndex] = default(T);

            return result;
        }

        public void AddRange(IEnumerable<T> collection)
        {
            AddLastRange(collection);
        }

        public void AddFirstRange(IEnumerable<T> collection)
        {
            AddFirstRange(collection, 0, DequeUtility.Count(collection));
        }

        public void AddFirstRange(
            IEnumerable<T> collection,
            int fromIndex,
            int count)
        {
            InsertRange(0, collection, fromIndex, count);
        }

        public void AddLastRange(IEnumerable<T> collection)
        {
            AddLastRange(collection, 0, DequeUtility.Count(collection));
        }

        public void AddLastRange(
            IEnumerable<T> collection,
            int fromIndex,
            int count)
        {
            InsertRange(this.Count, collection, fromIndex, count);
        }

        public void InsertRange(int index, IEnumerable<T> collection)
        {
            int count = DequeUtility.Count(collection);
            this.InsertRange(index, collection, 0, count);
        }

        public void InsertRange(
            int index,
            IEnumerable<T> collection,
            int fromIndex,
            int count)
        {
            checkIndexOutOfRange(index - 1);

            if (0 == count)
            {
                return;
            }

            ensureCapacityFor(count);

            if (index < this.Count / 2)
            {
                if (index > 0)
                {
                    int copyCount = index;
                    int shiftIndex = this.Capacity - count;
                    for (int j = 0; j < copyCount; j++)
                    {
                        buffer[toBufferIndex(shiftIndex + j)] =
                            buffer[toBufferIndex(j)];
                    }
                }

                this.shiftStartOffset(-count);

            }
            else
            {
                if (index < this.Count)
                {
                    int copyCount = this.Count - index;
                    int shiftIndex = index + count;
                    for (int j = 0; j < copyCount; j++)
                    {
                        buffer[toBufferIndex(shiftIndex + j)] =
                            buffer[toBufferIndex(index + j)];
                    }
                }
            }

            int i = index;
            foreach (T item in collection)
            {
                buffer[toBufferIndex(i)] = item;
                ++i;
            }

            incrementCount(count);
        }

        public void RemoveRange(int index, int count)
        {
            if (this.IsEmpty)
            {
                throw new InvalidOperationException("The Deque is empty");
            }
            if (index > Count - count)
            {
                throw new IndexOutOfRangeException(
                    "The supplied index is greater than the Count");
            }

            ClearBuffer(index, count);

            if (index == 0)
            {
                this.shiftStartOffset(count);
                this.Count -= count;
                return;
            }
            else if (index == Count - count)
            {
                this.Count -= count;
                return;
            }

            if ((index + (count / 2)) < Count / 2)
            {
                int copyCount = index;
                int writeIndex = count;
                for (int j = 0; j < copyCount; j++)
                {
                    buffer[toBufferIndex(writeIndex + j)]
                        = buffer[toBufferIndex(j)];
                }

                this.shiftStartOffset(count);
            }
            else
            {
                int copyCount = Count - count - index;
                int readIndex = index + count;
                for (int j = 0; j < copyCount; ++j)
                {
                    buffer[toBufferIndex(index + j)] =
                        buffer[toBufferIndex(readIndex + j)];
                }
            }

            decrementCount(count);
        }
        public T Get(int index)
        {
            checkIndexOutOfRange(index);
            return buffer[toBufferIndex(index)];
        }

        public void Set(int index, T item)
        {
            checkIndexOutOfRange(index);
            buffer[toBufferIndex(index)] = item;
        }

    }
}


using System;
using System.Linq;
using System.Collections.Generic;
namespace CodeForces22
{
	public class E
{
		public static void Main ()
		{
			int n = int.Parse(Console.ReadLine());
			int [] cameFrom = new int[n];
			for(int i=0;i<n;i++)
				cameFrom[i] = -1;

			var calls = Console.ReadLine().Split(' ').Select(str=>int.Parse(str)-1).ToArray();

			Dictionary<int,int> nodes = new Dictionary<int,int>();

			for(int i = 0;i<n;i++)
			{
				if(cameFrom[i] == -1)
				{
					int j = i;
					while(cameFrom[j] != i)
					{
						if(nodes.ContainsKey(j))
							nodes.Remove(j);
						cameFrom[j] = i;
						j = calls[j];
					}

					int sinkId = j;

					nodes.Add(i, sinkId);
				}
			}

			if(nodes.Count == 1)
			{
				HashSet<int> visited = new HashSet<int>();

				int ii = nodes.First().Value;

				if(ii == nodes.First().Key)
					{
						Console.WriteLine("0");
						return;
					}
				while(true)
				{
					if(ii == nodes.First().Value)
						break;
					ii = calls[ii];
					if(ii == nodes.First().Key)
					{
						Console.WriteLine("0");
						return;
					}
				}

			}

			Console.WriteLine(nodes.Count);

			var nArr = nodes.ToArray();
			for(int i=0;i<nodes.Count;i++)
			{
				int j = (i+1)%nodes.Count;
				Console.WriteLine("{0} {1}", nArr[i].Value+1, nArr[j].Key+1);
			}
		}
	}
}


using System;
using System.Linq;
using System.Collections.Generic;
namespace CodeForces22
{
	public class E
{
		public static void Main ()
		{
			int n = int.Parse(Console.ReadLine());
			int [] cameFrom = new int[n];
			for(int i=0;i<n;i++)
				cameFrom[i] = -1;

			var calls = Console.ReadLine().Split(' ').Select(str=>int.Parse(str)-1).ToArray();

			Dictionary<int,int> nodes = new Dictionary<int,int>();

			for(int i = 0;i<n;i++)
			{
				if(cameFrom[i] == -1)
				{
					int j = i;
					while(cameFrom[j] != i)
					{
						if(nodes.ContainsKey(j))
						{
							int sid = nodes[j];
							nodes.Remove(j);
							j = sid;
							break;
						}
						cameFrom[j] = i;
						j = calls[j];
					}

					int sinkId = j;

					nodes.Add(i, sinkId);
				}
			}

			if(nodes.Count == 1)
			{
				HashSet<int> visited = new HashSet<int>();

				int ii = nodes.First().Value;

				if(ii == nodes.First().Key)
					{
						Console.WriteLine("0");
						return;
					}
				while(true)
				{
					if(ii == nodes.First().Value)
						break;
					ii = calls[ii];
					if(ii == nodes.First().Key)
					{
						Console.WriteLine("0");
						return;
					}
				}
			}

			Console.WriteLine(nodes.Count);

			var nArr = nodes.ToArray();
			for(int i=0;i<nodes.Count;i++)
			{
				int j = (i+1)%nodes.Count;
				Console.WriteLine("{0} {1}", nArr[i].Value+1, nArr[j].Key+1);
			}
		}
	}
}


using System;
using System.Linq;
using System.Collections.Generic;
namespace CodeForces22
{
	public class E
{
		public static void Main ()
		{
			int n = int.Parse(Console.ReadLine());
			int [] cameFrom = new int[n];
			for(int i=0;i<n;i++)
				cameFrom[i] = -1;

			var calls = Console.ReadLine().Split(' ').Select(str=>int.Parse(str)-1).ToArray();

			Dictionary<int,int> nodes = new Dictionary<int,int>();

			for(int i = 0;i<n;i++)
			{
				if(cameFrom[i] == -1)
				{
					int j = i;
					while(cameFrom[j] != i)
					{
						if(nodes.ContainsKey(j))
							nodes.Remove(j);
						cameFrom[j] = i;
						j = calls[j];
					}

					int sinkId = j;

					nodes.Add(i, sinkId);
				}
			}

			Console.WriteLine(nodes.Count);

			var nArr = nodes.ToArray();
			for(int i=0;i<nodes.Count;i++)
			{
				int j = (i+1)%nodes.Count;
				Console.WriteLine("{0} {1}", nArr[i].Value+1, nArr[j].Key+1);
			}
		}
	}
}


package main

import (
	"bufio"
	"fmt"
	"os"
)

var (
	reader *bufio.Reader = bufio.NewReader(os.Stdin)
	writer *bufio.Writer = bufio.NewWriter(os.Stdout)
	Debug                = true
)

func Printf(f string, a ...interface{}) { fmt.Fprintf(writer, f, a...) }
func Scanf(f string, a ...interface{})  { fmt.Fscanf(reader, f, a...) }

func Dprint(format string, a ...interface{}) {
	if Debug {
		fmt.Fprintf(os.Stderr, format+"\n", a...)
	}
}

var (
	// input
	n int
	f []int

	eout []int   // forward adjacency
	ein  [][]int // reverse adjacency

	// dfs search
	visited   []bool  // whether we have visited this during dfs search.
	processed []bool  // whether we have visited out this vertex during dfs search.
	repr      []int   // representative out-vertex for a given vertex.
	inRepr    [][]int // inRepr[i] are vertices without any input edges belonging to the same component as out-vertex i
	reprList  []int   // list of unique representatives
)

func main() {
	defer writer.Flush()
	Scanf("%d\n", &n)

	// forward and reverse adjacency
	eout = make([]int, n)
	ein := make([][]int, n)

	for i := 0; i < n; i++ {
		var to int
		Scanf("%d", &to)
		to--
		eout[i] = to
		ein[to] = append(ein[to], i)
	}

	visited = make([]bool, n)
	processed = make([]bool, n)
	repr = make([]int, n)
	inRepr = make([][]int, n)

	// Populate repr and inRepr by running series of DFS.
	for i := 0; i < n; i++ {
		if visited[i] {
			continue
		}
		dfs(i)
		if len(ein[i]) == 0 {
			// i is vertex without in-edges.
			inRepr[repr[i]] = append(inRepr[repr[i]], i)
		}
	}

	Dprint("repr=%v, inRepr=%v, reprList=%v", repr, inRepr, reprList)

	type xy struct{ x, y int }
	var xys []xy
	// 1. connect all components within.
	for _, r := range reprList {
		if len(inRepr[r]) < 2 {
			// graph is either self-connected or has only one in/out pair.
			continue
		}
		for _, in := range inRepr[r][1:] {
			xys = append(xys, xy{r, in})
		}
	}

	Dprint("self-connections: %v", xys)

	// 2. connect all components together.
	reprList = append(reprList, reprList[0])
	for i := 0; i < len(reprList)-1; i++ {
		from := repr[reprList[i]] // Connect out-repr of reprList[i] to ...
		rto := reprList[i+1]      // ... first in-repr of reprList[i+1] ...
		to := inRepr[rto]
		if len(to) == 0 {
			// ... if that in-repr does not exist, use out-repr of reprList[i+1]
			to = []int{repr[rto]}
		}
		xys = append(xys, xy{from, to[0]})
	}

	Printf("%d\n", len(xys))
	for _, x := range xys {
		Printf("%d %d\n", x.x+1, x.y+1)
	}
}

// dfs will start dfs search and set representatives of all edges beginning with start.
func dfs(start int) {
	visited[start] = true

	nex := eout[start]
	if processed[nex] {
		// We have visited nex in previous iteration of DFS in main. Do nothing.
	} else if visited[nex] {
		// We have visited nex in this iteration of DFS. i.e. we have found a cycle and nex is out-representative now.
		repr[nex] = nex
		reprList = append(reprList, nex)
	} else {
		dfs(nex)
	}

	repr[start] = repr[nex]
	processed[start] = true
}


package main

import (
	"bufio"
	"fmt"
	"os"
)

var (
	reader *bufio.Reader = bufio.NewReader(os.Stdin)
	writer *bufio.Writer = bufio.NewWriter(os.Stdout)
	Debug                = true
)

func Printf(f string, a ...interface{}) { fmt.Fprintf(writer, f, a...) }
func Scanf(f string, a ...interface{})  { fmt.Fscanf(reader, f, a...) }

func Dprint(format string, a ...interface{}) {
	if Debug {
		fmt.Fprintf(os.Stderr, format+"\n", a...)
	}
}

var (
	// input
	n int
	f []int

	eout []int   // forward adjacency
	ein  [][]int // reverse adjacency

	// dfs search
	visited   []bool  // whether we have visited this during dfs search.
	processed []bool  // whether we have visited out this vertex during dfs search.
	repr      []int   // representative out-vertex for a given vertex.
	inRepr    [][]int // inRepr[i] are vertices without any input edges belonging to the same component as out-vertex i
	reprList  []int   // list of unique representatives
)

func main() {
	defer writer.Flush()
	Scanf("%d\n", &n)

	// forward and reverse adjacency
	eout = make([]int, n)
	ein := make([][]int, n)

	for i := 0; i < n; i++ {
		var to int
		Scanf("%d", &to)
		to--
		eout[i] = to
		ein[to] = append(ein[to], i)
	}

	visited = make([]bool, n)
	processed = make([]bool, n)
	repr = make([]int, n)
	inRepr = make([][]int, n)

	// Populate repr and inRepr by running series of DFS.
	for i := 0; i < n; i++ {
		if visited[i] {
			continue
		}
		dfs(i)
		if len(ein[i]) == 0 {
			// i is vertex without in-edges.
			inRepr[repr[i]] = append(inRepr[repr[i]], i)
		}
	}

	Dprint("repr=%v, inRepr=%v, reprList=%v", repr, inRepr, reprList)

	type xy struct{ x, y int }
	var xys []xy

	// 1. connect all components within.
	for _, r := range reprList {
		if len(inRepr[r]) < 2 {
			// graph is either self-connected or has only one in/out pair.
			continue
		}
		for _, in := range inRepr[r][1:] {
			xys = append(xys, xy{r, in})
		}
	}

	Dprint("self-connections: %v", xys)

	// 2. connect all components together.
	reprList = append(reprList, reprList[0])
	for i := 0; i < len(reprList)-1; i++ {
		from := repr[reprList[i]] // Connect out-repr of reprList[i] to ...
		rto := reprList[i+1]      // ... first in-repr of reprList[i+1] ...
		to := inRepr[rto]
		if len(to) == 0 {
			if len(reprList) == 2 {
				// edge case, we have only one component and it's already fully connected.
				continue
			}
			// ... if that in-repr does not exist, use out-repr of reprList[i+1]
			to = []int{repr[rto]}
		}
		xys = append(xys, xy{from, to[0]})
	}

	Printf("%d\n", len(xys))
	for _, x := range xys {
		Printf("%d %d\n", x.x+1, x.y+1)
	}
}

// dfs will start dfs search and set representatives of all edges beginning with start.
func dfs(start int) {
	visited[start] = true

	nex := eout[start]
	if processed[nex] {
		// We have visited nex in previous iteration of DFS in main. Do nothing.
	} else if visited[nex] {
		// We have visited nex in this iteration of DFS. i.e. we have found a cycle and nex is out-representative now.
		repr[nex] = nex
		reprList = append(reprList, nex)
	} else {
		dfs(nex)
	}

	repr[start] = repr[nex]
	processed[start] = true
}


import sys
from array import array  # noqa: F401

def input():
    return sys.stdin.buffer.readline().decode('utf-8')

n = int(input())
a = [0] + list(map(int, input().split()))
rev = [[] for _ in range(n + 1)]
indeg = [0] * (n + 1)

for i in range(1, n + 1):
    indeg[a[i]] += 1
    rev[a[i]].append(i)

_indeg = indeg[:]

for i in range(1, n + 1):
    v = i
    while indeg[v] == 0:
        indeg[a[v]] -= 1
        v = a[v]

visited = [0] * (n + 1)
group = []
group_leaf = []

for i in range(1, n + 1):
    if visited[i] or indeg[i] == 0:
        continue

    visited[i] = 1
    leaves = []
    stack = [i]

    while stack:
        v = stack.pop()
        if _indeg[v] == 0:
            leaves.append(v)
        for dest in rev[v]:
            if not visited[dest]:
                visited[dest] = 1
                stack.append(dest)

    group.append(i)
    group_leaf.append(leaves)

ans = []
if len(group) > 1:
    for i in range(len(group)):
        for j in group_leaf[(i + 1) % len(group)]:
            ans.append(f'{group[i]} {j}')
else:
    for j in group_leaf[0]:
        ans.append(f'{group[0]} {j}')

ans_str = str(len(ans)) + '\n' + '\n'.join(ans)
sys.stdout.buffer.write(ans_str.encode('utf-8'))


import sys
from array import array  # noqa: F401

def input():
    return sys.stdin.buffer.readline().decode('utf-8')

n = int(input())
a = [0] + list(map(int, input().split()))
rev = [[] for _ in range(n + 1)]
indeg = [0] * (n + 1)

for i in range(1, n + 1):
    indeg[a[i]] += 1
    rev[a[i]].append(i)

_indeg = indeg[:]

for i in range(1, n + 1):
    v = i
    while indeg[v] == 0:
        indeg[a[v]] -= 1
        v = a[v]

ans = []
group = [0] * (n + 1)
for i in range(1, n + 1):
    if group[i] or indeg[i] == 0:
        continue

    group[i] = i
    stack = [i]
    while stack:
        v = stack.pop()
        if _indeg[v] == 0:
            ans.append(f'{i} {v}')
        for dest in rev[v]:
            if not group[dest]:
                group[dest] = i
                stack.append(dest)

loops = list(set(group[1:]) - {0})
for i in range(len(loops) - 1):
    ans.append(f'{loops[i]} {loops[i+1]}')
    ans.append(f'{loops[i+1]} {loops[i]}')

ans_str = str(len(ans)) + '\n' + '\n'.join(ans)
sys.stdout.buffer.write(ans_str.encode('utf-8'))


import sys
from array import array  # noqa: F401

def input():
    return sys.stdin.buffer.readline().decode('utf-8')

n = int(input())
a = [0] + list(map(int, input().split()))
rev = [[] for _ in range(n + 1)]
indeg = [0] * (n + 1)

for i in range(1, n + 1):
    indeg[a[i]] += 1
    rev[a[i]].append(i)

_indeg = indeg[:]

for i in range(1, n + 1):
    v = i
    while indeg[v] == 0:
        indeg[a[v]] -= 1
        v = a[v]

visited = [0] * (n + 1)
group = []
group_leaf = []

for i in range(1, n + 1):
    if visited[i] or indeg[i] == 0:
        continue

    visited[i] = 1
    leaves = []
    stack = [i]

    while stack:
        v = stack.pop()
        if _indeg[v] == 0:
            leaves.append(v)
        for dest in rev[v]:
            if not visited[dest]:
                visited[dest] = 1
                stack.append(dest)

    if not leaves:
        leaves.append(i)
    group.append(i)
    group_leaf.append(leaves)

ans = []
m = len(group)

if not (m == 1 and group_leaf[0][0] == group[0]):
    for i in range(m):
        for j in group_leaf[(i + 1) % m]:
            ans.append(f'{group[i]} {j}')

if n == 12345:
    print(group)
    print(group_leaf)
    exit()

ans_str = str(len(ans)) + '\n' + '\n'.join(ans)
sys.stdout.buffer.write(ans_str.encode('utf-8'))


import sys
from array import array  # noqa: F401

def input():
    return sys.stdin.buffer.readline().decode('utf-8')

n = int(input())
a = [0] + list(map(int, input().split()))
rev = [[] for _ in range(n + 1)]
indeg = [0] * (n + 1)

for i in range(1, n + 1):
    indeg[a[i]] += 1
    rev[a[i]].append(i)

_indeg = indeg[:]

for i in range(1, n + 1):
    v = i
    while indeg[v] == 0:
        indeg[a[v]] -= 1
        v = a[v]

ans = []
group = [0] * (n + 1)
for i in range(1, n + 1):
    if group[i] or indeg[i] == 0:
        continue

    group[i] = i
    stack = [i]
    while stack:
        v = stack.pop()
        if _indeg[v] == 0:
            ans.append(f'{i} {v}')
        for dest in rev[v]:
            if not group[dest]:
                group[dest] = i
                stack.append(dest)

loops = list(set(group[1:]))
for i in range(len(loops) - 1):
    ans.append(f'{loops[i]} {loops[i+1]}')
    ans.append(f'{loops[i+1]} {loops[i]}')

ans_str = str(len(ans)) + '\n' + '\n'.join(ans)
sys.stdout.buffer.write(ans_str.encode('utf-8'))


import sys
from array import array  # noqa: F401

def input():
    return sys.stdin.buffer.readline().decode('utf-8')

n = int(input())
a = [0] + list(map(int, input().split()))
rev = [[] for _ in range(n + 1)]
indeg = [0] * (n + 1)

for i in range(1, n + 1):
    indeg[a[i]] += 1
    rev[a[i]].append(i)

_indeg = indeg[:]

for i in range(1, n + 1):
    v = i
    while indeg[v] == 0:
        indeg[a[v]] -= 1
        v = a[v]

visited = [0] * (n + 1)
group = []
group_leaf = []

for i in range(1, n + 1):
    if visited[i] or indeg[i] == 0:
        continue

    visited[i] = 1
    leaves = []
    stack = [i]

    while stack:
        v = stack.pop()
        if _indeg[v] == 0:
            leaves.append(v)
        for dest in rev[v]:
            if not visited[dest]:
                visited[dest] = 1
                stack.append(dest)

    group.append(i)
    group_leaf.append(leaves)

ans = []
m = len(group)
for i in range(m):
    for j in ([group[(i + 1) % m]] if m > 1 and not group_leaf[(i + 1) % m] else group_leaf[(i + 1) % m]):
        ans.append(f'{group[i]} {j}')

ans_str = str(len(ans)) + '\n' + '\n'.join(ans)
sys.stdout.buffer.write(ans_str.encode('utf-8'))


import sys
from array import array  # noqa: F401

def input():
    return sys.stdin.buffer.readline().decode('utf-8')

n = int(input())
a = [0] + list(map(int, input().split()))
rev = [[] for _ in range(n + 1)]
indeg = [0] * (n + 1)

for i in range(1, n + 1):
    indeg[a[i]] += 1
    rev[a[i]].append(i)

_indeg = indeg[:]

for i in range(1, n + 1):
    v = i
    while indeg[v] == 0:
        indeg[a[v]] -= 1
        v = a[v]

ans = []
group = [0] * (n + 1)
for i in range(1, n + 1):
    if group[i] or indeg[i] == 0:
        continue

    group[i] = i
    stack = [i]
    while stack:
        v = stack.pop()
        if _indeg[v] == 0:
            ans.append(f'{i} {v}')
        for dest in rev[v]:
            if not group[dest]:
                group[dest] = i
                stack.append(dest)

loops = list(set(group[1:]))
for i in range(len(loops) - 1):
    for j in range(i + 1, len(loops)):
        ans.append(f'{loops[i]} {loops[j]}')
        ans.append(f'{loops[j]} {loops[i]}')

ans_str = str(len(ans)) + '\n' + '\n'.join(ans)
sys.stdout.buffer.write(ans_str.encode('utf-8'))


import sys
from array import array  # noqa: F401

def input():
    return sys.stdin.buffer.readline().decode('utf-8')

n = int(input())
a = [0] + list(map(int, input().split()))
rev = [[] for _ in range(n + 1)]
indeg = [0] * (n + 1)

for i in range(1, n + 1):
    indeg[a[i]] += 1
    rev[a[i]].append(i)

_indeg = indeg[:]

for i in range(1, n + 1):
    v = i
    while indeg[v] == 0:
        indeg[a[v]] -= 1
        v = a[v]

visited = [0] * (n + 1)
group = []
group_leaf = []

for i in range(1, n + 1):
    if visited[i] or indeg[i] == 0:
        continue

    visited[i] = 1
    leaves = []
    stack = [i]

    while stack:
        v = stack.pop()
        if _indeg[v] == 0:
            leaves.append(v)
        for dest in rev[v]:
            if not visited[dest]:
                visited[dest] = 1
                stack.append(dest)

    if not leaves:
        leaves.append(i)
    group.append(i)
    group_leaf.append(leaves)

ans = []
m = len(group)

if not (m == 1 and group_leaf[0][0] == group[0]):
    for i in range(m):
        for j in group_leaf[(i + 1) % m]:
            ans.append(f'{group[i]} {j}')

ans_str = str(len(ans)) + '\n' + '\n'.join(ans)
sys.stdout.buffer.write(ans_str.encode('utf-8'))


import sys
from array import array  # noqa: F401

def input():
    return sys.stdin.buffer.readline().decode('utf-8')

n = int(input())
a = [0] + list(map(int, input().split()))
rev = [[] for _ in range(n + 1)]
indeg = [0] * (n + 1)

for i in range(1, n + 1):
    indeg[a[i]] += 1
    rev[a[i]].append(i)

_indeg = indeg[:]

for i in range(1, n + 1):
    v = i
    while indeg[v] == 0:
        indeg[a[v]] -= 1
        v = a[v]

ans = []
group = [0] * (n + 1)
for i in range(1, n + 1):
    if group[i] or indeg[i] == 0:
        continue

    group[i] = i
    stack = [i]
    while stack:
        v = stack.pop()
        if _indeg[v] == 0:
            ans.append(f'{i} {v}')
        for dest in rev[v]:
            if not group[dest]:
                group[dest] = i
                stack.append(dest)

loops = list(set(group[1:]) - {0})
for i in range(len(loops) - 1):
    ans.append(f'{loops[i]} {loops[i+1]}')
if len(loops) > 1:
    ans.append(f'{loops[-1]} {loops[0]}')
ans_str = str(len(ans)) + '\n' + '\n'.join(ans)
sys.stdout.buffer.write(ans_str.encode('utf-8'))


#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <set>
using namespace std;

#define FOR(i,j,k) for(int i=j;i<k;i++)
#define REP(i,j) for(int i=0;i<j;i++)
#define FORD(i,j,k) for(int i=j-1;i>=0;i--)
#define vi vector<int>
#define ll long long
#define pii pair<int,int>
#define st first
#define nd second
#define mp make_pair
#define pb push_back
#define ret return
#define N 1000005
#define INF 2000000001

struct song{
	int a,b,t,it; //t = 1 ->piosenka, t = 2 ->aktor
	song(int x,int y,int z,int i){
		a = x;b = y;t = z;it = i;
	}
};

bool operator<(song a,song b){
	if(a.a < b.a)
		ret 1;

	if(a.a > b.a)
		ret 0;

	if(a.t > b.t)
		ret 1;

	ret 0;
}

vector<song> C;
set<pii> S; //st -> koniec, nd -> iterator
pii A[N],B[N];
int T[N];
int n,m;
int res[N];

int main(){
	scanf("%d",&n);
	REP(i,n){
		scanf("%d%d",&A[i].st,&A[i].nd);
		C.pb(song(A[i].st,A[i].nd,1,i));
	}
	scanf("%d",&m);
	REP(i,m){
		scanf("%d%d%d",&B[i].st,&B[i].nd,&T[i]);
		C.pb(song(B[i].st,B[i].nd,2,i));
	}

	sort(C.begin(),C.end());
//	REP(i,C.size())
//		cout<<C[i].a<<" "<<C[i].b<<" "<<C[i].t<<endl;

	REP(i,C.size()){
//		cout<<"DUPA"<<endl;
		if(C[i].t == 2)
			S.insert(mp(C[i].b,C[i].it));
		else{
			//szukaj
			set<pii>::iterator it = S.end();
			if(S.size() != 0)it = S.lower_bound(mp(C[i].b,-1));
			if(it == S.end()||S.size() == 0)
				{printf("NO\n");ret 0;}

			T[(*it).nd]--;
			if(T[(*it).nd] == 0)
				S.erase(it);

			res[C[i].it] = (*it).nd+1;
		}
	}

	printf("YES\n");
	REP(i,n)
		printf("%d ",res[i]);

	printf("\n");

	ret 0;
}


#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <set>
using namespace std;

#define FOR(i,j,k) for(int i=j;i<k;i++)
#define REP(i,j) for(int i=0;i<j;i++)
#define FORD(i,j,k) for(int i=j-1;i>=0;i--)
#define vi vector<int>
#define ll long long
#define pii pair<int,int>
#define st first
#define nd second
#define mp make_pair
#define pb push_back
#define ret return
#define N 1000005
#define INF 2000000001

struct song{
	int a,b,t,it; //t = 1 ->piosenka, t = 2 ->aktor
	song(int x,int y,int z,int i){
		a = x;b = y;t = z;it = i;
	}
};

bool operator<(song a,song b){
	if(a.a < b.a)
		ret 1;

	if(a.a > b.a)
		ret 0;

	if(a.t > b.t)
		ret 1;

	ret 0;
}

vector<song> C;
set<pii> S; //st -> koniec, nd -> iterator
pii A[N],B[N];
int T[N];
int n,m;
int res[N];

int main(){
	scanf("%d",&n);
	REP(i,n){
		scanf("%d%d",&A[i].st,&A[i].nd);
		C.pb(song(A[i].st,A[i].nd,1,i));
	}
	scanf("%d",&m);
	REP(i,m){
		scanf("%d%d%d",&B[i].st,&B[i].nd,&T[i]);
		C.pb(song(B[i].st,B[i].nd,2,i));
	}

	sort(C.begin(),C.end());
//	REP(i,C.size())
//		cout<<C[i].a<<" "<<C[i].b<<" "<<C[i].t<<endl;

	REP(i,C.size()){
//		cout<<"DUPA"<<endl;
		if(C[i].t == 2)
			S.insert(mp(C[i].b,C[i].it));
		else{
			//szukaj
			set<pii>::iterator it = S.end();
			if(S.size() != 0)it = S.lower_bound(mp(C[i].b,-1));
			if(it == S.end()||S.size() == 0||T[(*it).nd] == 0)
				{printf("NO\n");ret 0;}

			T[(*it).nd]--;
			if(T[(*it).nd] <= 0)
				S.erase(it);

			res[C[i].it] = (*it).nd+1;
		}
	}

	printf("YES\n");
	REP(i,n)
		printf("%d ",res[i]);

	printf("\n");

	ret 0;
}


#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <set>
using namespace std;

#define FOR(i,j,k) for(int i=j;i<k;i++)
#define REP(i,j) for(int i=0;i<j;i++)
#define FORD(i,j,k) for(int i=j-1;i>=0;i--)
#define vi vector<int>
#define ll long long
#define pii pair<int,int>
#define st first
#define nd second
#define mp make_pair
#define pb push_back
#define ret return
#define N 100005
#define INF 2000000001

struct song{
	int a,b,t,it; //t = 1 ->piosenka, t = 2 ->aktor
	song(int x,int y,int z,int i = 0){
		a = x;b = y;t = z;it = i;
	}
};

bool operator<(song a,song b){
	if(a.a < b.a)
		ret 1;

	if(a.a > b.a)
		ret 0;

	if(a.t > b.t)
		ret 1;

	ret 0;
}

vector<song> C;
set<pii> S; //st -> koniec, nd -> iterator
pii A[N],B[N];
int T[N];
int n,m;
vi res;

int main(){
	scanf("%d",&n);
	REP(i,n){
		scanf("%d%d",&A[i].st,&A[i].nd);
		C.pb(song(A[i].st,A[i].nd,1));
	}
	scanf("%d",&m);
	REP(i,m){
		scanf("%d%d%d",&B[i].st,&B[i].nd,&T[i]);
		C.pb(song(B[i].st,B[i].nd,2,i));
	}

	sort(C.begin(),C.end());
//	REP(i,C.size())
//		cout<<C[i].a<<" "<<C[i].b<<" "<<C[i].t<<endl;

	REP(i,C.size()){
//		cout<<"DUPA"<<endl;
		if(C[i].t == 2)
			S.insert(mp(C[i].b,C[i].it));
		else{
			//szukaj
			set<pii>::iterator it = S.lower_bound(mp(C[i].b,0));
			if(it == S.end())
				{printf("NO\n");ret 0;}

			T[(*it).nd]--;
			if(T[(*it).nd] == 0)
				S.erase(*it);

			res.pb((*it).nd+1);
		}
	}

	printf("YES\n");
	REP(i,res.size())
		printf("%d ",res[i]);

	printf("\n");

	ret 0;
}


#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <set>
using namespace std;

#define FOR(i,j,k) for(int i=j;i<k;i++)
#define REP(i,j) for(int i=0;i<j;i++)
#define FORD(i,j,k) for(int i=j-1;i>=0;i--)
#define vi vector<int>
#define ll long long
#define pii pair<int,int>
#define st first
#define nd second
#define mp make_pair
#define pb push_back
#define ret return
#define N 100005
#define INF 2000000001

struct song{
	int a,b,t,it; //t = 1 ->piosenka, t = 2 ->aktor
	song(int x,int y,int z,int i = 0){
		a = x;b = y;t = z;it = i;
	}
};

bool operator<(song a,song b){
	if(a.a < b.a)
		ret 1;

	if(a.a > b.a)
		ret 0;

	if(a.t > b.t)
		ret 1;

	ret 0;
}

vector<song> C;
set<pii> S; //st -> koniec, nd -> iterator
pii A[N],B[N];
int T[N];
int n,m;
int res[N];

int main(){
	scanf("%d",&n);
	REP(i,n){
		scanf("%d%d",&A[i].st,&A[i].nd);
		C.pb(song(A[i].st,A[i].nd,1,i));
	}
	scanf("%d",&m);
	REP(i,m){
		scanf("%d%d%d",&B[i].st,&B[i].nd,&T[i]);
		C.pb(song(B[i].st,B[i].nd,2,i));
	}

	sort(C.begin(),C.end());
//	REP(i,C.size())
//		cout<<C[i].a<<" "<<C[i].b<<" "<<C[i].t<<endl;

	REP(i,C.size()){
//		cout<<"DUPA"<<endl;
		if(C[i].t == 2)
			S.insert(mp(C[i].b,C[i].it));
		else{
			//szukaj
			set<pii>::iterator it = S.lower_bound(mp(C[i].b,0));
			if(it == S.end())
				{printf("NO\n");ret 0;}

			T[(*it).nd]--;
			if(T[(*it).nd] == 0)
				S.erase(*it);

			res[C[i].it] = (*it).nd+1;
		}
	}

	printf("YES\n");
	REP(i,n)
		printf("%d ",res[i]);

	printf("\n");

	ret 0;
}


#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <set>
using namespace std;

#define FOR(i,j,k) for(int i=j;i<k;i++)
#define REP(i,j) for(int i=0;i<j;i++)
#define FORD(i,j,k) for(int i=j-1;i>=0;i--)
#define vi vector<int>
#define ll long long
#define pii pair<int,int>
#define st first
#define nd second
#define mp make_pair
#define pb push_back
#define ret return
#define N 1000005
#define INF 2000000001

struct song{
	int a,b,t,it; //t = 1 ->piosenka, t = 2 ->aktor
	song(int x,int y,int z,int i){
		a = x;b = y;t = z;it = i;
	}
};

bool operator<(song a,song b){
	if(a.a < b.a)
		ret 1;

	if(a.a > b.a)
		ret 0;

	if(a.t > b.t)
		ret 1;

	ret 0;
}

vector<song> C;
set<pii> S; //st -> koniec, nd -> iterator
pii A[N],B[N];
int T[N];
int n,m;
int res[N];

int main(){
	scanf("%d",&n);
	REP(i,n){
		scanf("%d%d",&A[i].st,&A[i].nd);
		C.pb(song(A[i].st,A[i].nd,1,i));
	}
	scanf("%d",&m);
	REP(i,m){
		scanf("%d%d%d",&B[i].st,&B[i].nd,&T[i]);
		C.pb(song(B[i].st,B[i].nd,2,i));
	}

	sort(C.begin(),C.end());
//	REP(i,C.size())
//		cout<<C[i].a<<" "<<C[i].b<<" "<<C[i].t<<endl;

	REP(i,C.size()){
//		cout<<"DUPA"<<endl;
		if(C[i].t == 2)
			S.insert(mp(C[i].b,C[i].it));
		else{
			//szukaj
			set<pii>::iterator it = S.end();
			if(S.size() != 0)it = S.lower_bound(mp(C[i].b,-1));
			if(it == S.end()||S.size() == 0)
				{printf("NO\n");ret 0;}

			T[(*it).nd]--;
			if(T[(*it).nd] == 0)
				S.erase(*it);

			res[C[i].it] = (*it).nd+1;
		}
	}

	printf("YES\n");
	REP(i,n)
		printf("%d ",res[i]);

	printf("\n");

	ret 0;
}


#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <set>
using namespace std;

#define FOR(i,j,k) for(int i=j;i<k;i++)
#define REP(i,j) for(int i=0;i<j;i++)
#define FORD(i,j,k) for(int i=j-1;i>=0;i--)
#define vi vector<int>
#define ll long long
#define pii pair<int,int>
#define st first
#define nd second
#define mp make_pair
#define pb push_back
#define ret return
#define N 1000005
#define INF 2000000001

struct song{
	int a,b,t,it; //t = 1 ->piosenka, t = 2 ->aktor
	song(int x,int y,int z,int i = 0){
		a = x;b = y;t = z;it = i;
	}
};

bool operator<(song a,song b){
	if(a.a < b.a)
		ret 1;

	if(a.a > b.a)
		ret 0;

	if(a.t > b.t)
		ret 1;

	ret 0;
}

vector<song> C;
set<pii> S; //st -> koniec, nd -> iterator
pii A[N],B[N];
int T[N];
int n,m;
int res[N];

int main(){
	scanf("%d",&n);
	REP(i,n){
		scanf("%d%d",&A[i].st,&A[i].nd);
		C.pb(song(A[i].st,A[i].nd,1,i));
	}
	scanf("%d",&m);
	REP(i,m){
		scanf("%d%d%d",&B[i].st,&B[i].nd,&T[i]);
		C.pb(song(B[i].st,B[i].nd,2,i));
	}

	sort(C.begin(),C.end());
//	REP(i,C.size())
//		cout<<C[i].a<<" "<<C[i].b<<" "<<C[i].t<<endl;

	REP(i,C.size()){
//		cout<<"DUPA"<<endl;
		if(C[i].t == 2)
			S.insert(mp(C[i].b,C[i].it));
		else{
			//szukaj
			set<pii>::iterator it = S.lower_bound(mp(C[i].b,0));
			if(it == S.end())
				{printf("NO\n");ret 0;}

			T[(*it).nd]--;
			if(T[(*it).nd] == 0)
				S.erase(*it);

			res[C[i].it] = (*it).nd+1;
		}
	}

	printf("YES\n");
	REP(i,n)
		printf("%d ",res[i]);

	printf("\n");

	ret 0;
}