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++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

#include <bits/stdc++.h>

using namespace std;

#define INF 100000000
#define YJ 1145141919
#define INF_INT_MAX 2147483647
#define INF_LL_MAX 9223372036854775807
#define EPS 1e-10
#define Pi 1
#define LL long long
#define ULL unsigned long long
#define LD long double

using namespace std;

#define MAX_N 200005

int V;
vector<int> G[MAX_N];
vector<int> rG[MAX_N];
vector<int> vs;
bool used[MAX_N];
int cmp[MAX_N];

vector<vector<int>> GG;

void add_edge(int from, int to)
{
  G[from].push_back(to);
  rG[to].push_back(from);
}

void dfs(int v)
{
  used[v] = true;
  for (int i = 0; i < G[v].size(); i++) {
    if(!used[G[v][i]]) dfs(G[v][i]);
  }
  vs.push_back(v);
}

void rdfs(int v, int k)
{
  used[v] = true;
  cmp[v] = k; GG[k].push_back(v);
  for (int i = 0; i < rG[v].size(); i++) {
    if(!used[rG[v][i]]) rdfs(rG[v][i], k);
  }
}

int scc()
{
  memset(used, 0, sizeof(used));
  vs.clear();
  for (int v = 0; v < V; v++) {
    if(!used[v]) dfs(v);
  }

  memset(used, 0, sizeof(used));
  int k = 0;
  for (int i = vs.size()-1; 0 <= i; i--) {
    if(!used[vs[i]]){
      GG.push_back(vector<int>());
      rdfs(vs[i], k++);
    }
  }

  return k;
}

bool LOOP[MAX_N];

bool USED[MAX_N*2];

int dist[MAX_N];
int grundy[MAX_N];

void check(int pos)
{
  if(used[pos]){
    return;
  }

  used[pos] = true;

  for (int i = 0; i < G[pos].size(); i++) {
    if(LOOP[G[pos][i]]){
      check(G[pos][i]);
      break;
    }
  }

  priority_queue<int, vector<int>, greater<int>> Set;

  for (int i = 0; i < G[pos].size(); i++) {
    Set.push(grundy[G[pos][i]]);
  }

  int g = 0;
  while(Set.size()){
    int p = Set.top();
    Set.pop();
    if(p == g){
      g++;
    }
    else{
      break;
    }
  }

  grundy[pos] = g;

  return;
}

int main()
{
  cin >> V;
  for (int i = 0; i < V; i++) {
    int a;
    cin >> a; a--;
    add_edge(a, i);
  }

  int K = scc();

  for (int i = 0; i < GG[0].size(); i++) {
    LOOP[GG[0][i]] = true;
  }

  memset(dist, -1, sizeof(dist));

  for (int i = 0; i < V; i++) {
    if(cmp[i] == 0){
      continue;
    }
    dist[K - 1 - cmp[i]] = i;
  }

/*
  cerr << "***" << endl;
  for (int i = 0; i < V; i++) {
    cerr << dist[i] << endl;
  }
*/


  memset(grundy, -1, sizeof(grundy));

  for (int i = 0; i < K-1; i++) {
    priority_queue<int, vector<int>, greater<int>> Set;
    int v = dist[i];
    for (int j = 0; j < G[v].size(); j++) {
      int next = G[v][j];
      Set.push(grundy[next]);
    }

    int g = 0;
    while(Set.size()){
      int p = Set.top();
      Set.pop();
      if(p == g){
        g++;
      }
      else{
        break;
      }
    }

    grundy[v] = g;
  }

  int G1, G2;
  int v = GG[0][0];
  priority_queue<int, vector<int>, greater<int>> Set;

  for (int j = 0; j < G[v].size(); j++) {
    int next = G[v][j];
    if(LOOP[next]){
      continue;
    }
    Set.push(grundy[next]);
  }

  int g = 0;
  while(Set.size()){
    int p = Set.top();
    if(p == g){
      g++;
    }
    else{
      break;
    }
    Set.pop();
  }

  G1 = g;

  while(Set.size()){
    int p = Set.top();
    if(p == g){
      g++;
    }
    else{
      break;
    }
    Set.pop();
  }

  G2 = g;
  if(G1 == G2){
    G2++;
  }

  cerr << G1 << " " << G2 << endl;

  grundy[v] = G1;
  memset(used, 0, sizeof(used));
  check(v);
  if(grundy[v] == G1){
    cout << "POSSIBLE" << endl;
    return 0;
  }

  grundy[v] = G2;
  memset(used, 0, sizeof(used));
  check(v);
  if(grundy[v] == G2){
    cout << "POSSIBLE" << endl;
    return 0;
  }

  cout << "IMPOSSIBLE" << endl;

  return 0;
}