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 Rust (1.15.1) (judge verdict: Accepted)

use std::io;
use std::io::{Read, Stdin};
use std::str;
use std::str::FromStr;
use std::usize;
use std::cmp;
use std::fmt::Debug;
use std::i64::MAX;
use std::collections::BinaryHeap;
use std::cmp::Ordering;
use std::collections::VecDeque;
use std::collections::BTreeSet;

static INVALID_GRUNDY: usize = 200000;

fn main() {
    let mut sc = Scanner::new();
    let n = sc.parse::<usize>();
    let p = (0..n).map(|_| { sc.parse::<usize>() - 1 }).collect::<Vec<_>>();

    let mut graph: Vec<Vec<usize>> = (0..n).map(|_| { Vec::new() }).collect::<Vec<Vec<_>>>();
    for i in 0..n {
        graph[p[i]].push(i);
    }

    let mut queue: VecDeque<usize> = VecDeque::new();
    let mut grundy = vec![INVALID_GRUNDY; n];
    let mut children_count = vec![0; n];

    for i in 0..n {
        if graph[i].is_empty() {
            grundy[i] = 0;
            queue.push_back(i);
        }
    }

    while !queue.is_empty() {
        let v = queue.pop_front().unwrap();
        let parent = p[v];
        children_count[parent] += 1;

        if children_count[parent] == graph[parent].len() {
            let mut children_set = BTreeSet::new();
            for c in &graph[parent] { children_set.insert(grundy[*c]); }
            for g in 0..n {
                if !children_set.contains(&g) {
                    grundy[parent] = g;
                    break;
                }
            }
            queue.push_back(parent);
        }
    }

    let mut start = n;
    for i in 0..n {
        if grundy[i] == INVALID_GRUNDY {
            start = i;
            break;
        }
    }
    if start == n {
        println!("POSSIBLE");
        return;
    }

    let mut start_children_set = BTreeSet::new();
    for c in &graph[start] {
        if grundy[*c] == INVALID_GRUNDY { continue; }
        start_children_set.insert(grundy[*c]);
    }

    let mut first_candidate = 0;
    loop {
        if !start_children_set.contains(&first_candidate) {
            break;
        }
        first_candidate += 1;
    }
    start_children_set.insert(first_candidate);
    let mut second_candidate = 0;
    loop {
        if !start_children_set.contains(&second_candidate) {
            break;
        }
        second_candidate += 1;
    }
    if dfs(start, first_candidate, &mut grundy, &graph, &p) {
        println!("POSSIBLE");
    } else if dfs(start, second_candidate, &mut grundy, &graph, &p) {
        println!("POSSIBLE");
    } else {
        println!("IMPOSSIBLE");
    }
}

fn dfs(k: usize, candidate: usize, grundy: &mut Vec<usize>, graph: &Vec<Vec<usize>>, p: &Vec<usize>) -> bool {
    if grundy[k] != INVALID_GRUNDY {
        if grundy[k] == candidate {
            return true;
        } else {
            return false;
        }
    }

    grundy[k] = candidate;
    let parent = p[k];
    let mut set = BTreeSet::new();
    for c in &graph[parent] {
        set.insert(grundy[*c]);
    }

    let mut parent_candidate = 0;
    loop {
        if !set.contains(&parent_candidate) {
            break;
        }
        parent_candidate += 1;
    }

    if dfs(parent, parent_candidate, grundy, graph, p) {
        return true;
    } else {
        grundy[k] = INVALID_GRUNDY;
        return false;
    }
}

struct Scanner {
    stdin: Stdin,
    buf: Vec<u8>,
}

impl Scanner {
    fn new() -> Scanner {
        Scanner {
            stdin: io::stdin(),
            buf: Vec::with_capacity(256),
        }
    }

    fn parse<T: FromStr>(&mut self) -> T
        where <T as FromStr>::Err: Debug
    {
        self.buf.clear();
        let mut it = self.stdin.lock().bytes();
        let mut c = it.next().unwrap().unwrap();
        while c == ' ' as u8 || c == '\n' as u8 {
            c = it.next().unwrap().unwrap();
        }
        while !(c == ' ' as u8 || c == '\n' as u8) {
            self.buf.push(c);
            c = it.next().unwrap().unwrap();
        }
        str::from_utf8(&self.buf).unwrap().parse::<T>().unwrap()
    }
}