Problem:
Score : 800 points

Problem Statement

There is a directed graph with N vertices and N edges. The vertices are numbered 1, 2, ..., N.

The graph has the following N edges: (p_1, 1), (p_2, 2), ..., (p_N, N), and the graph is weakly connected. Here, an edge from Vertex u to Vertex v is denoted by (u, v), and a weakly connected graph is a graph which would be connected if each edge was bidirectional.

We would like to assign a value to each of the vertices in this graph so that the following conditions are satisfied. Here, a_i is the value assigned to Vertex i.

Each a_i is a non-negative integer.

For each edge (i, j), a_i \neq a_j holds.

For each i and each integer x(0 ≤ x < a_i), there exists a vertex j such that the edge (i, j) exists and x = a_j holds.

Determine whether there exists such an assignment.

Constraints

2 ≤ N ≤ 200 000

1 ≤ p_i ≤ N

p_i \neq i

The graph is weakly connected.

Input

Input is given from Standard Input in the following format:

N
p_1 p_2 ... p_N

Output

If the assignment is possible, print POSSIBLE; otherwise, print IMPOSSIBLE.

Sample Input 1

4
2 3 4 1

Sample Output 1

POSSIBLE

The assignment is possible: {a_i} = {0, 1, 0, 1} or {a_i} = {1, 0, 1, 0}.

Sample Input 2

3
2 3 1

Sample Output 2

IMPOSSIBLE

Sample Input 3

4
2 3 1 1

Sample Output 3

POSSIBLE

The assignment is possible: {a_i} = {2, 0, 1, 0}.

Sample Input 4

6
4 5 6 5 6 4

Sample Output 4

IMPOSSIBLE

Solution in C# (Mono 4.6.2.0) (judge verdict: Runtime Error)

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
class Solve{
    List<int>[] G;
    List<int>[] G2;
    bool[] b;
    int[] grundy;
    int cycle1 = 0;
    int cycle2 = 0;
    public Solve(){}
    StringBuilder sb;
    public static int Main(){
        new Solve().Run();
        return 0;
    }
    void Run(){
        sb = new StringBuilder();
        Calc();
        Console.Write(sb.ToString());
    }
    void Calc(){
        int N = int.Parse(Console.ReadLine());
        string[] str = Console.ReadLine().Split(' ');
        int[] A = new int[N];
        for(int i=0;i<N;i++){
            A[i] = int.Parse(str[i])-1;
        }
        G = new List<int>[N];
        G2 = new List<int>[N];
        for(int i=0;i<N;i++){
            G[i] = new List<int>();
            G2[i] = new List<int>();
        }
        for(int i=0;i<N;i++){
            G[A[i]].Add(i);
            G2[A[i]].Add(i);
            G2[i].Add(A[i]);
        }
        b = new bool[N];
        GetCycle(0,-1);
        grundy = new int[N];
        b = new bool[N];
        for(int i=0;i<N;i++){
            if(!b[i]){
                dfs(i,-1);
            }
        }
        sb.Append(grundy[cycle1] == grundy[cycle2] ? "IMPOSSIBLE\n" : "POSSIBLE\n");
    }
    void GetCycle(int v,int f){
        b[v] = true;
        for(int i=0;i<G2[v].Count;i++){
            int t = G2[v][i];
            if(!b[t]){
                GetCycle(t,v);
            }
            else if(t != f){
                cycle1 = v;
                cycle2 = t;
            }
        }
    }
    int dfs(int v,int f){
        Heap H = new Heap(G[v].Count+1);
        for(int i=0;i<G[v].Count;i++){
            int t = G[v][i];
            if((t == cycle1 && v == cycle2) || (t == cycle2 && v == cycle1)){
                continue;
            }
            else{
                if(!b[t]){
                    dfs(t,v);
                }
                H.push(grundy[t]);
            }
        }
        int c = 0;
        int p = -1;
        while(H.size != 0){
            while(p < c){
                p = H.pop();
            }
            if(p == c){
                c++;
            }
            else{
                grundy[v] = c;
                return c;
            }
        }
        grundy[v] = c;
        return grundy[v];
    }
}
class Heap{
    public int size;
    int[] obj;
    public Heap(int maxsize){
        size = 0;
        obj = new int[maxsize];
    }
    public bool Compare(int a,int b){
        return a<=b;
    }
    public void push(int a){
        int i = size;
        size++;
        while(i > 0){
            int p = (i - 1)/2;
            if(Compare(obj[p],a)){
                obj[i] = a;
                break;
            }
            obj[i] = obj[p];
            i = p;
        }
        if(i == 0){
            obj[0] = a;
        }
    }
    public int pop(){
        int t = obj[0];
        int i = 0;
        size--;
        while(2*i+1 < size){
            int p = 2*i+1;
            if(p+1 < size && Compare(obj[p+1],obj[p])){
                p++;
            }
            if(Compare(obj[p],obj[size])){
                obj[i] = obj[p];
                i = p;
            }
            else{
                obj[i] = obj[size];
                break;
            }
        }
        if(2*i+1 >= size){
            obj[i] = obj[size];
        }
        return t;
    }
}