Submission #34093459


Source Code Expand

use std::cmp::Reverse;
use std::collections::BinaryHeap;

use proconio::input;

use nekolib::ds::{DecrementalUsizeSet, SkewHeap};

fn main() {
    input! {
        n: usize,
        a: [i64; n],
    }

    let mut repr = DecrementalUsizeSet::new(n);

    let mut uq = BinaryHeap::new();
    let mut q: Vec<_> = (0..n).map(|_| SkewHeap::new()).collect();
    let mut size = vec![1; n];

    for i in 0..n - 1 {
        uq.push((Reverse(a[i] + a[i + 1]), (i, 1), (i + 1, 1)));
    }

    let mut res = 0;
    let mut a: Vec<_> = a.iter().map(|&ai| Some(ai)).collect();
    while let Some((Reverse(cost), (i, si), (j, sj))) = uq.pop() {
        if !(size[i] == si && size[j] == sj) {
            continue;
        }

        let gi = repr.less_equal(i).unwrap();
        let gj = repr.less_equal(j).unwrap();
        q[gi].pop();
        q[gj].pop();

        res += cost;
        size[i] += std::mem::replace(&mut size[j], 0);
        a[i] = Some(cost);
        a[j].take();
        q[gi].push((Reverse(cost), (i, size[i])));

        if let Some(r) = repr.greater(j) {
            if size[r] > 1 {
                let tmp = std::mem::take(&mut q[r]);
                q[j].meld(tmp);
                repr.remove(r);
            }
        }
        if repr.less_equal(gi) != repr.less_equal(j) {
            let tmp = std::mem::take(&mut q[j]);
            q[gi].meld(tmp);
            repr.remove(j);
        }

        if let Some(r) = repr.greater(gi) {
            if size[r] > 1 {
                let tmp = std::mem::take(&mut q[r]);
                q[gi].meld(tmp);
                repr.remove(r);
            }
        }
        if let Some(l) = repr.less(gi) {
            if size[l] > 1 {
                let tmp = std::mem::take(&mut q[gi]);
                q[l].meld(tmp);
                repr.remove(gi);
            }
        }

        let i = repr.less_equal(gi).unwrap();
        let fst = q[i].peek().unwrap().clone();
        if let Some(l) = repr.less(i) {
            let ncost = a[l].unwrap() + (fst.0).0;
            uq.push((Reverse(ncost), (l, 1), fst.1));
        }
        if let Some(r) = repr.greater(i) {
            let ncost = a[r].unwrap() + (fst.0).0;
            uq.push((Reverse(ncost), fst.1, (r, 1)));
        }

        if let (Some(l), Some(r)) = (repr.less(i), repr.greater(i)) {
            let ncost = a[l].unwrap() + a[r].unwrap();
            uq.push((Reverse(ncost), (l, 1), (r, 1)));
        }

        if q[i].len() > 1 {
            let fst = q[i].pop().unwrap();
            let snd = q[i].peek().unwrap().clone();
            q[i].push(fst); // back
            let ncost = (fst.0).0 + (snd.0).0;
            let left = fst.1.min(snd.1);
            let right = fst.1.max(snd.1);
            uq.push((Reverse(ncost), left, right));
        }
    }

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

/// This module is bundled automatically.
/// See <https://rsk0315.github.io/library-rs/nekolib/> for documentation.
pub mod nekolib {
    pub mod ds {
        pub mod decremental_usize_set {
            pub struct DecrementalUsizeSet {
                u: usize,
                len: usize,
                small: Vec<usize>,
                large: UnionFind,
            }
            const WORD_SIZE: usize = 0_usize.count_zeros() as usize;
            fn bsf(i: usize) -> usize { i.trailing_zeros() as usize }
            fn bsr(i: usize) -> usize {
                WORD_SIZE - 1 - i.leading_zeros() as usize
            }
            impl DecrementalUsizeSet {
                pub fn new(u: usize) -> Self {
                    let mut small = vec![!0_usize; u / WORD_SIZE + 1];
                    let mut large = UnionFind::new(small.len() + 1);
                    let div = u / WORD_SIZE;
                    let rem = u % WORD_SIZE;
                    small[div] = !(!0_usize << rem);
                    if rem == 0 {
                        large.unite(div, div + 1);
                    }
                    Self { u, len: u, small, large }
                }
                pub fn universe_len(&self) -> usize { self.u }
                pub fn len(&self) -> usize { self.len }
                pub fn is_empty(&self) -> bool { self.len == 0 }
                pub fn contains(&self, i: usize) -> bool {
                    let div = i / WORD_SIZE;
                    let rem = i % WORD_SIZE;
                    div < self.small.len() && self.small[div] >> rem & 1 != 0
                }
                pub fn less(&self, i: usize) -> Option<usize> {
                    if i == 0 { None } else { self.less_equal(i - 1) }
                }
                pub fn less_equal(&self, i: usize) -> Option<usize> {
                    let i = i.min(self.u - 1) + 1;
                    let div = i / WORD_SIZE;
                    let rem = i % WORD_SIZE;
                    let m = self.small[div] & !(!0_usize << rem);
                    if m != 0 {
                        return Some(div * WORD_SIZE + bsr(m));
                    }
                    let b = self.large.left(div);
                    if b == 0 {
                        None
                    } else {
                        Some((b - 1) * WORD_SIZE + bsr(self.small[b - 1]))
                    }
                }
                pub fn greater(&self, i: usize) -> Option<usize> {
                    if i == self.u { None } else { self.greater_equal(i + 1) }
                }
                pub fn greater_equal(&self, i: usize) -> Option<usize> {
                    let div = i / WORD_SIZE;
                    let rem = i % WORD_SIZE;
                    if div >= self.small.len() {
                        return None;
                    }
                    let m = self.small[div] & !0_usize << rem;
                    if m != 0 {
                        return Some(div * WORD_SIZE + bsf(m));
                    }
                    let b = self.large.right(div + 1);
                    if b == self.small.len() {
                        None
                    } else {
                        Some(b * WORD_SIZE + bsf(self.small[b]))
                    }
                }
                pub fn remove(&mut self, i: usize) -> bool {
                    let div = i / WORD_SIZE;
                    let rem = i % WORD_SIZE;
                    if div >= self.small.len()
                        || self.small[div] >> rem & 1 == 0
                    {
                        return false;
                    }
                    self.len -= 1;
                    self.small[div] &= !(1_usize << rem);
                    if self.small[div] == 0 {
                        self.large.unite(div, div + 1);
                    }
                    true
                }
            }
            #[derive(Clone, Copy)]
            enum Item {
                Parent(usize),
                Size(usize),
            }
            use std::cell::RefCell;
            use Item::{Parent, Size};
            struct UnionFind {
                buf: RefCell<Vec<Item>>,
                left: Vec<usize>,
                right: Vec<usize>,
            }
            impl UnionFind {
                pub fn new(n: usize) -> Self {
                    Self {
                        buf: RefCell::new(vec![Size(1); n]),
                        left: (0..n).collect(),
                        right: (0..n).collect(),
                    }
                }
                fn repr(&self, mut i: usize) -> usize {
                    let mut buf = self.buf.borrow_mut();
                    let res = {
                        let mut i = i;
                        while let Parent(ni) = buf[i] {
                            i = ni;
                        }
                        i
                    };
                    while let Parent(ni) = buf[i] {
                        buf[i] = Parent(res);
                        i = ni;
                    }
                    res
                }
                pub fn left(&self, i: usize) -> usize {
                    self.left[self.repr(i)]
                }
                pub fn right(&self, i: usize) -> usize {
                    self.right[self.repr(i)]
                }
                pub fn unite(&mut self, il: usize, ir: usize) {
                    let il = self.repr(il);
                    let ir = self.repr(ir);
                    let mut buf = self.buf.borrow_mut();
                    let (sl, sr) = match (buf[il], buf[ir]) {
                        (Size(sl), Size(sr)) => (sl, sr),
                        _ => unreachable!(),
                    };
                    if sl < sr {
                        buf[ir] = Size(sl + sr);
                        buf[il] = Parent(ir);
                        self.left[ir] = self.left[il];
                    } else {
                        buf[il] = Size(sl + sr);
                        buf[ir] = Parent(il);
                        self.right[il] = self.right[ir];
                    }
                }
            }
        }
        pub use self::decremental_usize_set::DecrementalUsizeSet;
        pub mod skew_heap {
            pub struct SkewHeap<T> {
                root: Link<T>,
                len: usize,
            }
            type Link<T> = Option<Box<Node<T>>>;
            struct Node<T> {
                elem: T,
                left: Link<T>,
                right: Link<T>,
            }
            impl<T> Node<T> {
                pub fn new(elem: T) -> Self {
                    Self { elem, left: None, right: None }
                }
            }
            impl<T: Ord> SkewHeap<T> {
                pub fn new() -> Self { SkewHeap { root: None, len: 0 } }
                pub fn len(&self) -> usize { self.len }
                pub fn is_empty(&self) -> bool { self.len == 0 }
                pub fn clear(&mut self) { while self.pop().is_some() {} }
                pub fn peek(&self) -> Option<&T> {
                    self.root.as_ref().map(|node| &node.elem)
                }
                pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
                    if self.is_empty() {
                        None
                    } else {
                        Some(PeekMut { heap: self, tainted: false })
                    }
                }
                pub fn push(&mut self, elem: T) {
                    self.meld(Self {
                        root: Some(Box::new(Node::new(elem))),
                        len: 1,
                    });
                }
                pub fn pop(&mut self) -> Option<T> {
                    self.root.take().map(|node| {
                        self.len -= 1;
                        self.root = Self::meld_internal(node.left, node.right);
                        node.elem
                    })
                }
                pub fn meld(&mut self, other: Self) {
                    self.len += other.len;
                    self.root =
                        Self::meld_internal(self.root.take(), other.root);
                }
                fn meld_internal(left: Link<T>, right: Link<T>) -> Link<T> {
                    match (left, right) {
                        (left, None) => left,
                        (None, right) => right,
                        (Some(mut left), Some(right))
                            if left.elem >= right.elem =>
                        {
                            std::mem::swap(&mut left.left, &mut left.right);
                            left.left = Self::meld_internal(
                                left.left.take(),
                                Some(right),
                            );
                            Some(left)
                        }
                        (left, right) => Self::meld_internal(right, left),
                    }
                }
                fn fix_root(&mut self) {
                    let root = &self.root.as_ref().unwrap().elem;
                    let left = &self.root.as_ref().unwrap().left;
                    let right = &self.root.as_ref().unwrap().right;
                    if left
                        .as_ref()
                        .map(|left| &left.elem > root)
                        .unwrap_or(false)
                        || right
                            .as_ref()
                            .map(|right| &right.elem > root)
                            .unwrap_or(false)
                    {
                        let tmp = self.pop().unwrap();
                        self.push(tmp);
                    }
                }
            }
            impl<T> SkewHeap<T> {
                #[cfg(test)]
                fn push_with_dir(&mut self, elem: T, dir: &[bool]) {
                    let mut from = &mut self.root;
                    for &is_right in dir.iter().chain(std::iter::once(&false)) {
                        if let Some(v) = from {
                            from = if is_right {
                                &mut v.right
                            } else {
                                &mut v.left
                            };
                        } else if from.is_none() {
                            *from = Some(Box::new(Node::new(elem)));
                            return;
                        }
                    }
                }
                #[cfg(test)]
                fn in_order(&self) -> impl Iterator<Item = &T> {
                    fn dfs<'a, T>(v: &'a Link<T>, vec: &mut Vec<&'a T>) {
                        let v = match v {
                            Some(v) => v,
                            None => return,
                        };
                        dfs(&v.left, vec);
                        vec.push(&v.elem);
                        dfs(&v.right, vec);
                    }
                    let mut res = vec![];
                    dfs(&self.root, &mut res);
                    res.into_iter()
                }
                fn bfs_order(
                    &self,
                ) -> impl Iterator<Item = (&T, Option<&T>, Option<&T>)>
                {
                    use std::collections::VecDeque;
                    let mut res = vec![];
                    let mut q = VecDeque::new();
                    q.extend(self.root.as_ref());
                    while let Some(v) = q.pop_front() {
                        let left = v.left.as_ref();
                        let right = v.right.as_ref();
                        res.push((
                            &v.elem,
                            left.map(|o| &o.elem),
                            right.map(|o| &o.elem),
                        ));
                        q.extend(left.into_iter().chain(right));
                    }
                    res.into_iter()
                }
            }
            impl<T: Ord> Extend<T> for SkewHeap<T> {
                fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
                    for item in iter {
                        self.push(item);
                    }
                }
            }
            use std::iter::FromIterator;
            impl<T: Ord> FromIterator<T> for SkewHeap<T> {
                fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
                    let mut heap = Self::new();
                    heap.extend(iter);
                    heap
                }
            }
            pub struct IntoIter<T>(SkewHeap<T>);
            impl<T: Ord> IntoIterator for SkewHeap<T> {
                type IntoIter = IntoIter<T>;
                type Item = T;
                fn into_iter(self) -> Self::IntoIter { IntoIter(self) }
            }
            impl<T: Ord> Iterator for IntoIter<T> {
                type Item = T;
                fn next(&mut self) -> Option<Self::Item> { self.0.pop() }
                fn size_hint(&self) -> (usize, Option<usize>) {
                    (self.0.len, Some(self.0.len))
                }
            }
            impl<T: Ord> ExactSizeIterator for IntoIter<T> {
                fn len(&self) -> usize { self.0.len }
            }
            pub struct PeekMut<'a, T: 'a + Ord> {
                heap: &'a mut SkewHeap<T>,
                tainted: bool,
            }
            use std::ops::{Deref, DerefMut};
            impl<T: Ord> Drop for PeekMut<'_, T> {
                fn drop(&mut self) {
                    if self.tainted {
                        self.heap.fix_root();
                    }
                }
            }
            impl<T: Ord> Deref for PeekMut<'_, T> {
                type Target = T;
                fn deref(&self) -> &T { &self.heap.root.as_ref().unwrap().elem }
            }
            impl<T: Ord> DerefMut for PeekMut<'_, T> {
                fn deref_mut(&mut self) -> &mut T {
                    self.tainted = true;
                    &mut self.heap.root.as_mut().unwrap().elem
                }
            }
            impl<'a, T: Ord> PeekMut<'a, T> {
                pub fn pop(mut self) -> T {
                    let value = self.heap.pop().unwrap();
                    self.tainted = false;
                    value
                }
            }
            impl<T: Ord> Default for SkewHeap<T> {
                fn default() -> Self { Self::new() }
            }
            use std::fmt;
            impl<T: fmt::Debug> fmt::Debug for SkewHeap<T> {
                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                    f.debug_list()
                        .entries(self.bfs_order().map(|(x, ..)| x))
                        .finish()
                }
            }
        }
        pub use self::skew_heap::SkewHeap;
    }
}

Submission Info

Submission Time
Task N - Slimes
User rsk0315
Language Rust (1.42.0)
Score 100
Code Size 18099 Byte
Status AC
Exec Time 7 ms
Memory 2252 KiB

Judge Result

Set Name All
Score / Max Score 100 / 100
Status
AC × 16
Set Name Test Cases
All 0_00, 0_01, 0_02, 0_03, 1_00, 1_01, 1_02, 1_03, 1_04, 1_05, 1_06, 1_07, 1_08, 1_09, 1_10, 1_11
Case Name Status Exec Time Memory
0_00 AC 7 ms 2000 KiB
0_01 AC 2 ms 2080 KiB
0_02 AC 2 ms 2112 KiB
0_03 AC 3 ms 1996 KiB
1_00 AC 1 ms 2128 KiB
1_01 AC 2 ms 2164 KiB
1_02 AC 2 ms 2144 KiB
1_03 AC 2 ms 2036 KiB
1_04 AC 2 ms 2220 KiB
1_05 AC 2 ms 2148 KiB
1_06 AC 2 ms 2128 KiB
1_07 AC 2 ms 2252 KiB
1_08 AC 2 ms 2168 KiB
1_09 AC 2 ms 2184 KiB
1_10 AC 1 ms 2244 KiB
1_11 AC 2 ms 2148 KiB