Submission #33728625


Source Code Expand

use std::collections::HashSet;

use dsu::*;
use proconio::{input, marker::Usize1};

fn main() {
    input! {
        n: usize,
        m: usize,
        p: [Usize1; n],
        xy: [(Usize1, Usize1); m]
    };

    let mut dsu = Dsu::new(n);
    for (x, y) in xy {
        dsu.merge(x, y);
    }

    let mut ans = 0_usize;
    for group in dsu.groups() {
        let s1 = group.iter().copied().collect::<HashSet<usize>>();
        let s2 = group
            .iter()
            .copied()
            .map(|g| p[g])
            .collect::<HashSet<usize>>();
        ans += s1.intersection(&s2).collect::<HashSet<_>>().len();
    }

    println!("{}", ans);
}

//https://github.com/rust-lang-ja/ac-library-rs

pub mod dsu {
    /// Implement (union by size) + (path compression)
    /// Reference:
    /// Zvi Galil and Giuseppe F. Italiano,
    /// Data structures and algorithms for disjoint set union problems
    pub struct Dsu {
        n: usize,
        // root node: -1 * component size
        // otherwise: parent
        parent_or_size: Vec<i32>,
    }

    impl Dsu {
        // 0 <= size <= 10^8 is constrained.
        pub fn new(size: usize) -> Self {
            Self {
                n: size,
                parent_or_size: vec![-1; size],
            }
        }
        pub fn merge(&mut self, a: usize, b: usize) -> usize {
            assert!(a < self.n);
            assert!(b < self.n);
            let (mut x, mut y) = (self.leader(a), self.leader(b));
            if x == y {
                return x;
            }
            if -self.parent_or_size[x] < -self.parent_or_size[y] {
                std::mem::swap(&mut x, &mut y);
            }
            self.parent_or_size[x] += self.parent_or_size[y];
            self.parent_or_size[y] = x as i32;
            x
        }

        pub fn same(&mut self, a: usize, b: usize) -> bool {
            assert!(a < self.n);
            assert!(b < self.n);
            self.leader(a) == self.leader(b)
        }
        pub fn leader(&mut self, a: usize) -> usize {
            assert!(a < self.n);
            if self.parent_or_size[a] < 0 {
                return a;
            }
            self.parent_or_size[a] = self.leader(self.parent_or_size[a] as usize) as i32;
            self.parent_or_size[a] as usize
        }
        pub fn size(&mut self, a: usize) -> usize {
            assert!(a < self.n);
            let x = self.leader(a);
            -self.parent_or_size[x] as usize
        }
        pub fn groups(&mut self) -> Vec<Vec<usize>> {
            let mut leader_buf = vec![0; self.n];
            let mut group_size = vec![0; self.n];
            for i in 0..self.n {
                leader_buf[i] = self.leader(i);
                group_size[leader_buf[i]] += 1;
            }
            let mut result = vec![Vec::new(); self.n];
            for i in 0..self.n {
                result[i].reserve(group_size[i]);
            }
            for i in 0..self.n {
                result[leader_buf[i]].push(i);
            }
            result
                .into_iter()
                .filter(|x| !x.is_empty())
                .collect::<Vec<Vec<usize>>>()
        }
    }

    #[cfg(test)]
    mod tests {
        use super::*;

        #[test]
        fn dsu_works() {
            let mut d = Dsu::new(4);
            d.merge(0, 1);
            assert_eq!(d.same(0, 1), true);
            d.merge(1, 2);
            assert_eq!(d.same(0, 2), true);
            assert_eq!(d.size(0), 3);
            assert_eq!(d.same(0, 3), false);
            assert_eq!(d.groups(), vec![vec![0, 1, 2], vec![3]]);
        }
    }
}

Submission Info

Submission Time
Task D - Equals
User bouzuya
Language Rust (1.42.0)
Score 400
Code Size 3617 Byte
Status AC
Exec Time 50 ms
Memory 15832 KiB

Judge Result

Set Name Sample All
Score / Max Score 0 / 0 400 / 400
Status
AC × 4
AC × 23
Set Name Test Cases
Sample 0_000.txt, 0_001.txt, 0_002.txt, 0_003.txt
All 0_000.txt, 0_001.txt, 0_002.txt, 0_003.txt, 1_004.txt, 1_005.txt, 1_006.txt, 1_007.txt, 1_008.txt, 1_009.txt, 1_010.txt, 1_011.txt, 1_012.txt, 1_013.txt, 1_014.txt, 1_015.txt, 1_016.txt, 1_017.txt, 1_018.txt, 1_019.txt, 1_020.txt, 1_021.txt, 1_022.txt
Case Name Status Exec Time Memory
0_000.txt AC 4 ms 2152 KiB
0_001.txt AC 2 ms 2016 KiB
0_002.txt AC 1 ms 2056 KiB
0_003.txt AC 2 ms 2180 KiB
1_004.txt AC 13 ms 4236 KiB
1_005.txt AC 50 ms 15832 KiB
1_006.txt AC 49 ms 10028 KiB
1_007.txt AC 1 ms 2076 KiB
1_008.txt AC 1 ms 2052 KiB
1_009.txt AC 2 ms 2068 KiB
1_010.txt AC 1 ms 1992 KiB
1_011.txt AC 2 ms 2028 KiB
1_012.txt AC 2 ms 1984 KiB
1_013.txt AC 2 ms 2208 KiB
1_014.txt AC 3 ms 2076 KiB
1_015.txt AC 2 ms 2152 KiB
1_016.txt AC 2 ms 2212 KiB
1_017.txt AC 3 ms 2148 KiB
1_018.txt AC 15 ms 4124 KiB
1_019.txt AC 41 ms 13260 KiB
1_020.txt AC 42 ms 13236 KiB
1_021.txt AC 42 ms 13044 KiB
1_022.txt AC 47 ms 11216 KiB