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::str::FromStr;

#[allow(dead_code)]
fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

type Weight = i32;
#[allow(dead_code)]
#[derive(Clone, Debug, Eq, PartialEq)]
struct Edge {
    index: usize,
    src: usize,
    dest: usize,
    weight: Weight,
}
#[allow(dead_code)]
impl Edge {
    fn new(index: usize, src: usize, dest: usize, weight: Weight) -> Edge {
        Edge {
            index: index,
            src: src,
            dest: dest,
            weight: weight,
        }
    }
}
impl std::cmp::Ord for Edge {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        (self.weight, self.src, self.dest).cmp(&(other.weight, other.src, other.dest))
    }
}
impl std::cmp::PartialOrd for Edge {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}
type Edges = Vec<Edge>;
type Graph = Vec<Edges>;
#[allow(dead_code)]
fn graph_new(n: usize) -> Graph {
    vec![vec![]; n]
}
#[allow(dead_code)]
fn add_bi_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    graph[dest].push(Edge::new(*index, dest, src, weight));
    *index += 1;
}
#[allow(dead_code)]
fn add_uni_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    *index += 1;
}

fn get_grundy_number(from: usize, graph: &Graph, grundy: &Vec<i32>, add_value: i32) -> i32 {
    let mut childs = vec![];
    if add_value != -1 {
        childs.push(add_value);
    }
    for edge in graph[from].iter() {
        if grundy[edge.dest] == -1 {
            continue;
        }
        childs.push(grundy[edge.dest]);
    }
    childs.sort();
    childs.dedup();
    for i in 0..childs.len() {
        if childs[i] != i as i32 {
            return i as i32;
        }
    }
    childs.len() as i32
}

fn naive(graph: &Graph, rev_graph: &Graph, grundy: &mut Vec<i32>) {
    let n = graph.len();
    let mut cnts = vec![0; n];
    let mut stack = vec![];
    for i in 0..n {
        if grundy[i] != -1 {
            continue;
        }
        for edge in graph[i].iter() {
            if grundy[edge.dest] != -1 {
                continue;
            }
            cnts[i] += 1;
        }
        if cnts[i] == 0 {
            stack.push(i);
        }
    }
    while let Some(from) = stack.pop() {
        grundy[from] = get_grundy_number(from, &graph, &grundy, -1);
        for edge in rev_graph[from].iter() {
            let to = edge.dest;
            if grundy[to] != -1 {
                continue;
            }
            cnts[to] -= 1;
            if cnts[to] == 0 {
                stack.push(to);
            }
        }
    }
}

fn get_target(grundy: &Vec<i32>) -> Option<usize> {
    let n = grundy.len();
    for i in 0..n {
        if grundy[i] == -1 {
            return Some(i);
        }
    }
    None
}

fn valid(graph: &Graph, grundy: &Vec<i32>) -> bool {
    let n = graph.len();
    for i in 0..n {
        if grundy[i] == -1 || grundy[i] != get_grundy_number(i, graph, grundy, -1) {
            return false;
        }
    }
    true
}

fn main() {
    let n = read::<usize>();
    let mut graph = graph_new(n);
    let mut rev_graph = graph_new(n);
    let mut e = 0;
    for i in 0..n {
        let from = read::<usize>() - 1;
        add_uni_edge(&mut graph, &mut e, from, i, 0);
        e -= 1;
        add_uni_edge(&mut rev_graph, &mut e, i, from, 0);
    }
    let mut grundy = vec![-1; n];
    naive(&graph, &rev_graph, &mut grundy);
    // println!("{:?}", grundy);
    let target = get_target(&grundy);
    if let Some(target) = target {
        let min_number = get_grundy_number(target, &graph, &grundy, -1);
        let next_number = get_grundy_number(target, &graph, &grundy, min_number);
        for &candidate in [min_number, next_number].iter() {
            let mut temp_grundy = grundy.clone();
            temp_grundy[target] = candidate;
            naive(&graph, &rev_graph, &mut temp_grundy);
            // println!("{:?}", temp_grundy);
            if valid(&graph, &temp_grundy) {
                println!("POSSIBLE");
                return;
            }
        }
    } else {
        println!("POSSIBLE");
        return;
    }
    println!("IMPOSSIBLE");
}