Submission #62131403
Source Code Expand
// https://atcoder.jp/contests/arc191/tasks/arc191_d
use crate::algo_lib::collections::default_map::DefaultHashMap;
use crate::algo_lib::collections::min_max::MinimMaxim;
use crate::algo_lib::collections::vec_ext::inc_dec::IncDec;
use crate::algo_lib::graph::edge_distances::EdgeAlgos;
use crate::algo_lib::graph::Graph;
use crate::algo_lib::io::input::Input;
use crate::algo_lib::io::output::Output;
use crate::algo_lib::misc::test_type::TaskType;
use crate::algo_lib::misc::test_type::TestType;
type PreCalc = ();
fn solve(input: &mut Input, out: &mut Output, _test_case: usize, _data: &mut PreCalc) {
let n = input.read_size();
let m = input.read_size();
let s = input.read_size() - 1;
let t = input.read_size() - 1;
let edges = input.read_size_pair_vec(m).dec();
let graph = Graph::with_biedges(n, &edges);
let ds = graph.edge_distances(s);
let dt = graph.edge_distances(t);
let direct = ds[t];
let mut by_d = DefaultHashMap::new(Vec::new());
for i in 0..n {
by_d[(ds[i], dt[i])].push(i);
}
let mut ans = None;
for ((ds, dt), verts) in by_d {
if verts.len() > 1 {
ans.minim(2 * (ds + dt));
}
if ds + dt != direct && ds.abs_diff(dt) != direct {
ans.minim(direct + ds + dt);
}
}
out.print_line(ans);
}
pub static TEST_TYPE: TestType = TestType::Single;
pub static TASK_TYPE: TaskType = TaskType::Classic;
pub(crate) fn run(mut input: Input, mut output: Output) -> bool {
let mut pre_calc = ();
match TEST_TYPE {
TestType::Single => solve(&mut input, &mut output, 1, &mut pre_calc),
TestType::MultiNumber => {
let t = input.read();
for i in 1..=t {
solve(&mut input, &mut output, i, &mut pre_calc);
}
}
TestType::MultiEof => {
let mut i = 1;
while input.peek().is_some() {
solve(&mut input, &mut output, i, &mut pre_calc);
i += 1;
}
}
}
output.flush();
match TASK_TYPE {
TaskType::Classic => input.is_empty(),
TaskType::Interactive => true,
}
}
fn main() {
let input = crate::algo_lib::io::input::Input::stdin();
let output = crate::algo_lib::io::output::Output::stdout();
run(input, output);
}
pub mod algo_lib {
pub mod collections {
pub mod default_map {
use crate::algo_lib::collections::fx_hash_map::FxHashMap;
use std::collections::BTreeMap;
use std::fmt::Debug;
use std::hash::Hash;
use std::ops::{Deref, DerefMut, Index, IndexMut};
macro_rules! default_map {
(
$name:ident, $inner:ident, $key_trait:path, $into_values:ident, $into_iter:ident
) => {
#[derive(Clone, Eq, PartialEq, Debug, Default)] pub struct $name < K : Eq +
$key_trait, V > { inner : $inner < K, V >, default : V, } impl < K : Eq +
$key_trait, V > Deref for $name < K, V > { type Target = $inner < K, V >; fn
deref(& self) -> & Self::Target { & self.inner } } impl < K : Eq + $key_trait, V
> DerefMut for $name < K, V > { fn deref_mut(& mut self) -> & mut Self::Target {
& mut self.inner } } impl < K : Eq + $key_trait, V : Clone > $name < K, V > { pub
fn new(default : V) -> Self { Self { inner : $inner ::default(), default, } } pub
fn get(& self, key : & K) -> & V { self.inner.get(key).unwrap_or(& self.default)
} pub fn get_mut(& mut self, key : K) -> & mut V { self.inner.entry(key)
.or_insert_with(|| self.default.clone()) } pub fn into_values(self) ->
$into_values < K, V > { self.inner.into_values() } } impl < K : Eq + $key_trait,
V : Clone > Index < K > for $name < K, V > { type Output = V; fn index(& self,
index : K) -> & Self::Output { self.get(& index) } } impl < K : Eq + $key_trait,
V : Clone > IndexMut < K > for $name < K, V > { fn index_mut(& mut self, index :
K) -> & mut Self::Output { self.get_mut(index) } } impl < K : Eq + $key_trait, V
> IntoIterator for $name < K, V > { type Item = (K, V); type IntoIter =
$into_iter < K, V >; fn into_iter(self) -> Self::IntoIter { self.inner
.into_iter() } } impl < K : Eq + $key_trait, V : Default > FromIterator < (K, V)
> for $name < K, V > { fn from_iter < T : IntoIterator < Item = (K, V) >> (iter :
T) -> Self { Self { inner : $inner ::from_iter(iter), default : V::default(), } }
}
};
}
type HashMapIntoValues<K, V> = std::collections::hash_map::IntoValues<K, V>;
type HashMapIntoIter<K, V> = std::collections::hash_map::IntoIter<K, V>;
default_map!(DefaultHashMap, FxHashMap, Hash, HashMapIntoValues, HashMapIntoIter);
type TreeMapIntoValues<K, V> = std::collections::btree_map::IntoValues<K, V>;
type TreeMapIntoIter<K, V> = std::collections::btree_map::IntoIter<K, V>;
default_map!(DefaultTreeMap, BTreeMap, Ord, TreeMapIntoValues, TreeMapIntoIter);
pub fn qty<T: Eq + Hash + Clone>(arr: &[T]) -> DefaultHashMap<T, usize> {
let mut map = DefaultHashMap::new(0);
for item in arr {
map[item.clone()] += 1;
}
map
}
pub fn by_index<T: Eq + Hash + Clone>(arr: &[T]) -> DefaultHashMap<T, Vec<usize>> {
let mut map = DefaultHashMap::new(Vec::new());
for (i, item) in arr.iter().enumerate() {
map[item.clone()].push(i);
}
map
}
}
pub mod dsu {
use crate::algo_lib::collections::slice_ext::bounds::Bounds;
use crate::algo_lib::collections::slice_ext::indices::Indices;
use std::cell::Cell;
#[derive(Clone)]
pub struct DSU {
id: Vec<Cell<i32>>,
count: usize,
}
impl DSU {
pub fn new(n: usize) -> Self {
Self {
id: vec![Cell::new(- 1); n],
count: n,
}
}
pub fn size(&self, i: usize) -> usize {
(-self.id[self.find(i)].get()) as usize
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.id.len()
}
pub fn iter(&self) -> impl Iterator<Item = usize> + '_ {
self.id
.iter()
.enumerate()
.filter_map(|(i, id)| if id.get() < 0 { Some(i) } else { None })
}
pub fn set_count(&self) -> usize {
self.count
}
pub fn union(&mut self, mut a: usize, mut b: usize) -> bool {
a = self.find(a);
b = self.find(b);
if a == b {
false
} else {
self.id[a].set(self.id[a].get() + self.id[b].get());
self.id[b].set(a as i32);
self.count -= 1;
true
}
}
pub fn find(&self, i: usize) -> usize {
if self.id[i].get() >= 0 {
let res = self.find(self.id[i].get() as usize);
self.id[i].set(res as i32);
res
} else {
i
}
}
pub fn clear(&mut self) {
self.count = self.id.len();
self.id.fill(Cell::new(-1));
}
pub fn parts(&self) -> Vec<Vec<usize>> {
let roots: Vec<_> = self.iter().collect();
let mut res = vec![Vec::new(); roots.len()];
for i in self.id.indices() {
res[roots.as_slice().bin_search(&self.find(i)).unwrap()].push(i);
}
res
}
}
}
pub mod fx_hash_map {
use crate::algo_lib::misc::lazy_lock::LazyLock;
use std::convert::TryInto;
use std::time::SystemTime;
use std::{
collections::{HashMap, HashSet},
hash::{BuildHasherDefault, Hasher},
ops::BitXor,
};
pub type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
pub type FxHashSet<V> = HashSet<V, BuildHasherDefault<FxHasher>>;
#[derive(Default)]
pub struct FxHasher {
hash: usize,
}
static K: LazyLock<usize> = LazyLock::new(|| {
((SystemTime::UNIX_EPOCH.elapsed().unwrap().as_nanos().wrapping_mul(2) + 1)
& 0xFFFFFFFFFFFFFFFF) as usize
});
impl FxHasher {
#[inline]
fn add_to_hash(&mut self, i: usize) {
self.hash = self.hash.rotate_left(5).bitxor(i).wrapping_mul(*K);
}
}
impl Hasher for FxHasher {
#[inline]
fn write(&mut self, mut bytes: &[u8]) {
let read_usize = |bytes: &[u8]| u64::from_ne_bytes(
bytes[..8].try_into().unwrap(),
);
let mut hash = FxHasher { hash: self.hash };
while bytes.len() >= 8 {
hash.add_to_hash(read_usize(bytes) as usize);
bytes = &bytes[8..];
}
if bytes.len() >= 4 {
hash.add_to_hash(
u32::from_ne_bytes(bytes[..4].try_into().unwrap()) as usize,
);
bytes = &bytes[4..];
}
if bytes.len() >= 2 {
hash.add_to_hash(
u16::from_ne_bytes(bytes[..2].try_into().unwrap()) as usize,
);
bytes = &bytes[2..];
}
if !bytes.is_empty() {
hash.add_to_hash(bytes[0] as usize);
}
self.hash = hash.hash;
}
#[inline]
fn write_u8(&mut self, i: u8) {
self.add_to_hash(i as usize);
}
#[inline]
fn write_u16(&mut self, i: u16) {
self.add_to_hash(i as usize);
}
#[inline]
fn write_u32(&mut self, i: u32) {
self.add_to_hash(i as usize);
}
#[inline]
fn write_u64(&mut self, i: u64) {
self.add_to_hash(i as usize);
}
#[inline]
fn write_usize(&mut self, i: usize) {
self.add_to_hash(i);
}
#[inline]
fn finish(&self) -> u64 {
self.hash as u64
}
}
}
pub mod iter_ext {
pub mod iters {
use std::iter::{Chain, Enumerate, Filter, Map, Rev, Skip, StepBy, Sum, Take, Zip};
pub trait Iters: IntoIterator + Sized {
fn iter_enumerate(self) -> Enumerate<Self::IntoIter> {
self.into_iter().enumerate()
}
fn iter_rev(self) -> Rev<Self::IntoIter>
where
Self::IntoIter: DoubleEndedIterator,
{
self.into_iter().rev()
}
fn iter_skip(self, n: usize) -> Skip<Self::IntoIter> {
self.into_iter().skip(n)
}
fn iter_take(self, n: usize) -> Take<Self::IntoIter> {
self.into_iter().take(n)
}
fn iter_chain<V: IntoIterator<Item = Self::Item>>(
self,
chained: V,
) -> Chain<Self::IntoIter, V::IntoIter> {
self.into_iter().chain(chained)
}
fn iter_zip<V: IntoIterator>(self, other: V) -> Zip<Self::IntoIter, V::IntoIter> {
self.into_iter().zip(other)
}
fn iter_max(self) -> Self::Item
where
Self::Item: Ord,
{
self.into_iter().max().unwrap()
}
fn iter_max_by_key<B, F>(self, f: F) -> Self::Item
where
F: FnMut(&Self::Item) -> B,
B: Ord,
{
self.into_iter().max_by_key(f).unwrap()
}
fn iter_min(self) -> Self::Item
where
Self::Item: Ord,
{
self.into_iter().min().unwrap()
}
fn iter_min_by_key<B, F>(self, f: F) -> Self::Item
where
F: FnMut(&Self::Item) -> B,
B: Ord,
{
self.into_iter().min_by_key(f).unwrap()
}
fn iter_sum(self) -> Self::Item
where
Self::Item: Sum<Self::Item>,
{
Sum::sum(self.into_iter())
}
fn iter_map<F, T>(self, f: F) -> Map<Self::IntoIter, F>
where
F: FnMut(Self::Item) -> T,
{
self.into_iter().map(f)
}
fn iter_all(self, f: impl FnMut(Self::Item) -> bool) -> bool {
self.into_iter().all(f)
}
fn iter_any(self, f: impl FnMut(Self::Item) -> bool) -> bool {
self.into_iter().any(f)
}
fn iter_step_by(self, step: usize) -> StepBy<Self::IntoIter> {
self.into_iter().step_by(step)
}
fn iter_filter<F: FnMut(&Self::Item) -> bool>(
self,
f: F,
) -> Filter<Self::IntoIter, F> {
self.into_iter().filter(f)
}
fn iter_fold<Acc, F>(self, init: Acc, f: F) -> Acc
where
F: FnMut(Acc, Self::Item) -> Acc,
{
self.into_iter().fold(init, f)
}
fn iter_reduce<F>(self, f: F) -> Option<Self::Item>
where
F: FnMut(Self::Item, Self::Item) -> Self::Item,
{
self.into_iter().reduce(f)
}
fn iter_position<P>(self, predicate: P) -> Option<usize>
where
P: FnMut(Self::Item) -> bool,
{
self.into_iter().position(predicate)
}
fn iter_find(self, val: Self::Item) -> Option<usize>
where
Self::Item: PartialEq,
{
self.into_iter().position(|x| x == val)
}
fn iter_count(self, val: Self::Item) -> usize
where
Self::Item: PartialEq,
{
self.into_iter().filter(|x| *x == val).count()
}
}
impl<U> Iters for U
where
U: IntoIterator,
{}
}
pub mod min_max {
use crate::algo_lib::collections::min_max::MinimMaxim;
pub trait IterMinMaxPos<'a, T: Ord + 'a>: 'a
where
&'a Self: IntoIterator<Item = T>,
{
fn max_position(&'a self) -> usize {
let mut res = None;
let mut val = None;
for (i, cur) in self.into_iter().enumerate() {
if val.maxim(cur) {
res = Some(i);
}
}
res.unwrap()
}
fn min_position(&'a self) -> usize {
let mut res = None;
let mut val = None;
for (i, cur) in self.into_iter().enumerate() {
if val.minim(cur) {
res = Some(i);
}
}
res.unwrap()
}
}
impl<'a, T: Ord + 'a, I: ?Sized + 'a> IterMinMaxPos<'a, T> for I
where
&'a I: IntoIterator<Item = T>,
{}
}
}
pub mod min_max {
pub trait MinimMaxim<Rhs = Self>: PartialOrd + Sized {
fn minim(&mut self, other: Rhs) -> bool;
fn maxim(&mut self, other: Rhs) -> bool;
}
impl<T: PartialOrd> MinimMaxim for T {
fn minim(&mut self, other: Self) -> bool {
if other < *self {
*self = other;
true
} else {
false
}
}
fn maxim(&mut self, other: Self) -> bool {
if other > *self {
*self = other;
true
} else {
false
}
}
}
impl<T: PartialOrd> MinimMaxim<T> for Option<T> {
fn minim(&mut self, other: T) -> bool {
match self {
None => {
*self = Some(other);
true
}
Some(v) => v.minim(other),
}
}
fn maxim(&mut self, other: T) -> bool {
match self {
None => {
*self = Some(other);
true
}
Some(v) => v.maxim(other),
}
}
}
}
pub mod slice_ext {
pub mod bounds {
use std::ops::{Bound, RangeBounds};
pub trait Bounds<T: PartialOrd> {
fn lower_bound(&self, el: &T) -> usize;
fn upper_bound(&self, el: &T) -> usize;
fn bin_search(&self, el: &T) -> Option<usize>;
fn more(&self, el: &T) -> usize;
fn more_or_eq(&self, el: &T) -> usize;
fn less(&self, el: &T) -> usize {
self.lower_bound(el)
}
fn less_or_eq(&self, el: &T) -> usize {
self.upper_bound(el)
}
fn inside<'a>(&self, bounds: impl RangeBounds<&'a T>) -> usize
where
T: 'a;
}
impl<T: PartialOrd> Bounds<T> for [T] {
fn lower_bound(&self, el: &T) -> usize {
let mut left = 0;
let mut right = self.len();
while left < right {
let mid = left + ((right - left) >> 1);
if &self[mid] < el {
left = mid + 1;
} else {
right = mid;
}
}
left
}
fn upper_bound(&self, el: &T) -> usize {
let mut left = 0;
let mut right = self.len();
while left < right {
let mid = left + ((right - left) >> 1);
if &self[mid] <= el {
left = mid + 1;
} else {
right = mid;
}
}
left
}
fn bin_search(&self, el: &T) -> Option<usize> {
let at = self.lower_bound(el);
if at == self.len() || &self[at] != el { None } else { Some(at) }
}
fn more(&self, el: &T) -> usize {
self.len() - self.upper_bound(el)
}
fn more_or_eq(&self, el: &T) -> usize {
self.len() - self.lower_bound(el)
}
fn inside<'a>(&self, bounds: impl RangeBounds<&'a T>) -> usize
where
T: 'a,
{
let to = match bounds.end_bound() {
Bound::Included(el) => self.less_or_eq(el),
Bound::Excluded(el) => self.less(el),
Bound::Unbounded => self.len(),
};
let from = match bounds.start_bound() {
Bound::Included(el) => self.less(el),
Bound::Excluded(el) => self.less_or_eq(el),
Bound::Unbounded => 0,
};
to - from
}
}
}
pub mod indices {
use std::ops::Range;
pub trait Indices {
fn indices(&self) -> Range<usize>;
}
impl<T> Indices for [T] {
fn indices(&self) -> Range<usize> {
0..self.len()
}
}
}
}
pub mod vec_ext {
pub mod inc_dec {
use crate::algo_lib::numbers::num_traits::algebra::{AdditionMonoidWithSub, One};
pub trait IncDec {
#[must_use]
fn inc(self) -> Self;
#[must_use]
fn dec(self) -> Self;
}
impl<T: AdditionMonoidWithSub + One> IncDec for T {
fn inc(self) -> Self {
self + T::one()
}
fn dec(self) -> Self {
self - T::one()
}
}
impl<T: AdditionMonoidWithSub + One> IncDec for Vec<T> {
fn inc(mut self) -> Self {
self.iter_mut().for_each(|i| *i += T::one());
self
}
fn dec(mut self) -> Self {
self.iter_mut().for_each(|i| *i -= T::one());
self
}
}
impl<T: AdditionMonoidWithSub + One> IncDec for Vec<Vec<T>> {
fn inc(mut self) -> Self {
self.iter_mut().for_each(|v| v.iter_mut().for_each(|i| *i += T::one()));
self
}
fn dec(mut self) -> Self {
self.iter_mut().for_each(|v| v.iter_mut().for_each(|i| *i -= T::one()));
self
}
}
impl<T: AdditionMonoidWithSub + One, U: AdditionMonoidWithSub + One> IncDec
for Vec<(T, U)> {
fn inc(mut self) -> Self {
self.iter_mut()
.for_each(|(i, j)| {
*i += T::one();
*j += U::one();
});
self
}
fn dec(mut self) -> Self {
self.iter_mut()
.for_each(|(i, j)| {
*i -= T::one();
*j -= U::one();
});
self
}
}
impl<T: AdditionMonoidWithSub + One, U: AdditionMonoidWithSub + One, V> IncDec
for Vec<(T, U, V)> {
fn inc(mut self) -> Self {
self.iter_mut()
.for_each(|(i, j, _)| {
*i += T::one();
*j += U::one();
});
self
}
fn dec(mut self) -> Self {
self.iter_mut()
.for_each(|(i, j, _)| {
*i -= T::one();
*j -= U::one();
});
self
}
}
impl<T: AdditionMonoidWithSub + One, U: AdditionMonoidWithSub + One, V, W> IncDec
for Vec<(T, U, V, W)> {
fn inc(mut self) -> Self {
self.iter_mut()
.for_each(|(i, j, ..)| {
*i += T::one();
*j += U::one();
});
self
}
fn dec(mut self) -> Self {
self.iter_mut()
.for_each(|(i, j, ..)| {
*i -= T::one();
*j -= U::one();
});
self
}
}
impl<T: AdditionMonoidWithSub + One, U: AdditionMonoidWithSub + One, V, W, X> IncDec
for Vec<(T, U, V, W, X)> {
fn inc(mut self) -> Self {
self.iter_mut()
.for_each(|(i, j, ..)| {
*i += T::one();
*j += U::one();
});
self
}
fn dec(mut self) -> Self {
self.iter_mut()
.for_each(|(i, j, ..)| {
*i -= T::one();
*j -= U::one();
});
self
}
}
impl<T: AdditionMonoidWithSub + One, U: AdditionMonoidWithSub + One> IncDec for (T, U) {
fn inc(mut self) -> Self {
self.0 += T::one();
self.1 += U::one();
self
}
fn dec(mut self) -> Self {
self.0 -= T::one();
self.1 -= U::one();
self
}
}
}
}
}
pub mod graph {
use crate::algo_lib::collections::dsu::DSU;
use crate::algo_lib::graph::edges::bi_edge::BiEdge;
use crate::algo_lib::graph::edges::edge::Edge;
use crate::algo_lib::graph::edges::edge_trait::{BidirectionalEdgeTrait, EdgeTrait};
use std::ops::{Index, IndexMut};
#[derive(Clone)]
pub struct Graph<E: EdgeTrait> {
edges: Vec<Vec<E>>,
edge_count: usize,
}
impl<E: EdgeTrait> Graph<E> {
pub fn new(vertex_count: usize) -> Self {
Self {
edges: vec![Vec::new(); vertex_count],
edge_count: 0,
}
}
pub fn add_edge(&mut self, (from, mut edge): (usize, E)) -> usize {
let to = edge.to();
assert!(to < self.vertex_count());
let direct_id = self.edges[from].len();
edge.set_id(self.edge_count);
self.edges[from].push(edge);
if E::REVERSABLE {
let rev_id = self.edges[to].len();
self.edges[from][direct_id].set_reverse_id(rev_id);
let mut rev_edge = self.edges[from][direct_id].reverse_edge(from);
rev_edge.set_id(self.edge_count);
rev_edge.set_reverse_id(direct_id);
self.edges[to].push(rev_edge);
}
self.edge_count += 1;
direct_id
}
pub fn add_vertices(&mut self, cnt: usize) {
self.edges.resize(self.edges.len() + cnt, Vec::new());
}
pub fn clear(&mut self) {
self.edge_count = 0;
for ve in self.edges.iter_mut() {
ve.clear();
}
}
pub fn vertex_count(&self) -> usize {
self.edges.len()
}
pub fn edge_count(&self) -> usize {
self.edge_count
}
pub fn degrees(&self) -> Vec<usize> {
self.edges.iter().map(|v| v.len()).collect()
}
}
impl<E: BidirectionalEdgeTrait> Graph<E> {
pub fn is_tree(&self) -> bool {
if self.edge_count + 1 != self.vertex_count() {
false
} else {
self.is_connected()
}
}
pub fn is_forest(&self) -> bool {
let mut dsu = DSU::new(self.vertex_count());
for i in 0..self.vertex_count() {
for e in self[i].iter() {
if i <= e.to() && !dsu.union(i, e.to()) {
return false;
}
}
}
true
}
pub fn is_connected(&self) -> bool {
let mut dsu = DSU::new(self.vertex_count());
for i in 0..self.vertex_count() {
for e in self[i].iter() {
dsu.union(i, e.to());
}
}
dsu.set_count() == 1
}
}
impl<E: EdgeTrait> Index<usize> for Graph<E> {
type Output = [E];
fn index(&self, index: usize) -> &Self::Output {
&self.edges[index]
}
}
impl<E: EdgeTrait> IndexMut<usize> for Graph<E> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.edges[index]
}
}
impl Graph<Edge<()>> {
pub fn with_edges(n: usize, edges: &[(usize, usize)]) -> Self {
let mut graph = Self::new(n);
for &(from, to) in edges {
graph.add_edge(Edge::new(from, to));
}
graph
}
}
impl<P: Clone> Graph<Edge<P>> {
pub fn with_edges_with_payload(n: usize, edges: &[(usize, usize, P)]) -> Self {
let mut graph = Self::new(n);
for (from, to, p) in edges.iter() {
graph.add_edge(Edge::with_payload(*from, *to, p.clone()));
}
graph
}
}
impl Graph<BiEdge<()>> {
pub fn with_biedges(n: usize, edges: &[(usize, usize)]) -> Self {
let mut graph = Self::new(n);
for &(from, to) in edges {
graph.add_edge(BiEdge::new(from, to));
}
graph
}
}
impl<P: Clone> Graph<BiEdge<P>> {
pub fn with_biedges_with_payload(n: usize, edges: &[(usize, usize, P)]) -> Self {
let mut graph = Self::new(n);
for (from, to, p) in edges.iter() {
graph.add_edge(BiEdge::with_payload(*from, *to, p.clone()));
}
graph
}
}
pub mod edge_distances {
use crate::algo_lib::collections::iter_ext::iters::Iters;
use crate::algo_lib::collections::iter_ext::min_max::IterMinMaxPos;
use crate::algo_lib::graph::edges::edge_trait::{BidirectionalEdgeTrait, EdgeTrait};
use crate::algo_lib::graph::Graph;
use std::collections::VecDeque;
pub trait EdgeAlgos {
fn edge_distances(&self, source: usize) -> Vec<u32>;
}
pub trait BiEdgeAlgos: EdgeAlgos {
fn centers(&self) -> Vec<usize>;
fn diameter(&self) -> usize;
}
impl<E: EdgeTrait> EdgeAlgos for Graph<E> {
fn edge_distances(&self, source: usize) -> Vec<u32> {
let mut dist = vec![u32::MAX; self.vertex_count()];
dist[source] = 0;
let mut q = VecDeque::new();
q.push_back(source);
while !q.is_empty() {
let cur = q.pop_front().unwrap();
for e in self[cur].iter() {
let next = e.to();
if dist[next] == u32::MAX {
dist[next] = dist[cur] + 1;
q.push_back(next);
}
}
}
dist
}
}
impl<E: BidirectionalEdgeTrait> BiEdgeAlgos for Graph<E> {
fn centers(&self) -> Vec<usize> {
debug_assert!(self.is_tree());
if self.vertex_count() == 0 {
return Vec::new();
}
let d0 = self.edge_distances(0);
let first = d0.max_position();
let d1 = self.edge_distances(first);
let second = d1.max_position();
let d2 = self.edge_distances(second);
let mut res = Vec::new();
let r1 = d1[second] / 2;
let r2 = (d1[second] + 1) / 2;
for (i, (d1, d2)) in d1.iter().zip(d2.iter()).enumerate() {
if *d1 == r1 && *d2 == r2 || *d1 == r2 && *d2 == r1 {
res.push(i);
}
}
res
}
fn diameter(&self) -> usize {
debug_assert!(self.is_tree());
let d0 = self.edge_distances(0);
let first = d0.max_position();
let d1 = self.edge_distances(first);
d1.iter_max() as usize
}
}
}
pub mod edges {
pub mod bi_edge {
use crate::algo_lib::graph::edges::bi_edge_trait::BiEdgeTrait;
use crate::algo_lib::graph::edges::edge_id::{EdgeId, NoId, WithId};
use crate::algo_lib::graph::edges::edge_trait::{BidirectionalEdgeTrait, EdgeTrait};
#[derive(Clone)]
pub struct BiEdgeRaw<Id: EdgeId, P> {
to: u32,
id: Id,
payload: P,
}
impl<Id: EdgeId> BiEdgeRaw<Id, ()> {
pub fn new(from: usize, to: usize) -> (usize, Self) {
(
from,
Self {
to: to as u32,
id: Id::new(),
payload: (),
},
)
}
}
impl<Id: EdgeId, P> BiEdgeRaw<Id, P> {
pub fn with_payload(from: usize, to: usize, payload: P) -> (usize, Self) {
(from, Self::with_payload_impl(to, payload))
}
fn with_payload_impl(to: usize, payload: P) -> BiEdgeRaw<Id, P> {
Self {
to: to as u32,
id: Id::new(),
payload,
}
}
}
impl<Id: EdgeId, P: Clone> BidirectionalEdgeTrait for BiEdgeRaw<Id, P> {}
impl<Id: EdgeId, P: Clone> EdgeTrait for BiEdgeRaw<Id, P> {
type Payload = P;
const REVERSABLE: bool = true;
fn to(&self) -> usize {
self.to as usize
}
fn id(&self) -> usize {
self.id.id()
}
fn set_id(&mut self, id: usize) {
self.id.set_id(id);
}
fn reverse_id(&self) -> usize {
panic!("no reverse id")
}
fn set_reverse_id(&mut self, _: usize) {}
fn reverse_edge(&self, from: usize) -> Self {
Self::with_payload_impl(from, self.payload.clone())
}
fn payload(&self) -> &P {
&self.payload
}
}
impl<Id: EdgeId, P: Clone> BiEdgeTrait for BiEdgeRaw<Id, P> {}
pub type BiEdge<P> = BiEdgeRaw<NoId, P>;
pub type BiEdgeWithId<P> = BiEdgeRaw<WithId, P>;
}
pub mod bi_edge_trait {
use crate::algo_lib::graph::edges::edge_trait::EdgeTrait;
pub trait BiEdgeTrait: EdgeTrait {}
}
pub mod edge {
use crate::algo_lib::graph::edges::edge_id::{EdgeId, NoId, WithId};
use crate::algo_lib::graph::edges::edge_trait::EdgeTrait;
#[derive(Clone)]
pub struct EdgeRaw<Id: EdgeId, P> {
to: u32,
id: Id,
payload: P,
}
impl<Id: EdgeId> EdgeRaw<Id, ()> {
pub fn new(from: usize, to: usize) -> (usize, Self) {
(
from,
Self {
to: to as u32,
id: Id::new(),
payload: (),
},
)
}
}
impl<Id: EdgeId, P> EdgeRaw<Id, P> {
pub fn with_payload(from: usize, to: usize, payload: P) -> (usize, Self) {
(from, Self::with_payload_impl(to, payload))
}
fn with_payload_impl(to: usize, payload: P) -> Self {
Self {
to: to as u32,
id: Id::new(),
payload,
}
}
}
impl<Id: EdgeId, P: Clone> EdgeTrait for EdgeRaw<Id, P> {
type Payload = P;
const REVERSABLE: bool = false;
fn to(&self) -> usize {
self.to as usize
}
fn id(&self) -> usize {
self.id.id()
}
fn set_id(&mut self, id: usize) {
self.id.set_id(id);
}
fn reverse_id(&self) -> usize {
panic!("no reverse")
}
fn set_reverse_id(&mut self, _: usize) {
panic!("no reverse")
}
fn reverse_edge(&self, _: usize) -> Self {
panic!("no reverse")
}
fn payload(&self) -> &P {
&self.payload
}
}
pub type Edge<P> = EdgeRaw<NoId, P>;
pub type EdgeWithId<P> = EdgeRaw<WithId, P>;
}
pub mod edge_id {
pub trait EdgeId: Clone {
fn new() -> Self;
fn id(&self) -> usize;
fn set_id(&mut self, id: usize);
}
#[derive(Clone)]
pub struct WithId {
id: u32,
}
impl EdgeId for WithId {
fn new() -> Self {
Self { id: 0 }
}
fn id(&self) -> usize {
self.id as usize
}
fn set_id(&mut self, id: usize) {
self.id = id as u32;
}
}
#[derive(Clone)]
pub struct NoId {}
impl EdgeId for NoId {
fn new() -> Self {
Self {}
}
fn id(&self) -> usize {
panic!("Id called on no id")
}
fn set_id(&mut self, _: usize) {}
}
}
pub mod edge_trait {
pub trait EdgeTrait: Clone {
type Payload;
const REVERSABLE: bool;
fn to(&self) -> usize;
fn id(&self) -> usize;
fn set_id(&mut self, id: usize);
fn reverse_id(&self) -> usize;
fn set_reverse_id(&mut self, reverse_id: usize);
#[must_use]
fn reverse_edge(&self, from: usize) -> Self;
fn payload(&self) -> &Self::Payload;
}
pub trait BidirectionalEdgeTrait: EdgeTrait {}
}
}
}
pub mod io {
pub mod input {
use std::fs::File;
use std::io::{Read, Stdin};
use std::mem::MaybeUninit;
enum InputSource {
Stdin(Stdin),
File(File),
Slice,
Delegate(Box<dyn Read + Send>),
}
pub struct Input {
input: InputSource,
buf: Vec<u8>,
at: usize,
buf_read: usize,
eol: bool,
}
macro_rules! read_impl {
($t:ty, $read_name:ident, $read_vec_name:ident) => {
pub fn $read_name (& mut self) -> $t { self.read() } pub fn $read_vec_name (& mut
self, len : usize) -> Vec <$t > { self.read_vec(len) }
};
($t:ty, $read_name:ident, $read_vec_name:ident, $read_pair_vec_name:ident) => {
read_impl!($t, $read_name, $read_vec_name); pub fn $read_pair_vec_name (& mut
self, len : usize) -> Vec < ($t, $t) > { self.read_vec(len) }
};
}
impl Input {
const DEFAULT_BUF_SIZE: usize = 4096;
pub fn slice(input: &[u8]) -> Self {
Self {
input: InputSource::Slice,
buf: input.to_vec(),
at: 0,
buf_read: input.len(),
eol: true,
}
}
pub fn stdin() -> Self {
Self {
input: InputSource::Stdin(std::io::stdin()),
buf: vec![0; Self::DEFAULT_BUF_SIZE],
at: 0,
buf_read: 0,
eol: true,
}
}
pub fn file(file: File) -> Self {
Self {
input: InputSource::File(file),
buf: vec![0; Self::DEFAULT_BUF_SIZE],
at: 0,
buf_read: 0,
eol: true,
}
}
pub fn delegate(reader: impl Read + Send + 'static) -> Self {
Self {
input: InputSource::Delegate(Box::new(reader)),
buf: vec![0; Self::DEFAULT_BUF_SIZE],
at: 0,
buf_read: 0,
eol: true,
}
}
pub fn get(&mut self) -> Option<u8> {
if self.refill_buffer() {
let res = self.buf[self.at];
self.at += 1;
if res == b'\r' {
self.eol = true;
if self.refill_buffer() && self.buf[self.at] == b'\n' {
self.at += 1;
}
return Some(b'\n');
}
self.eol = res == b'\n';
Some(res)
} else {
None
}
}
pub fn peek(&mut self) -> Option<u8> {
if self.refill_buffer() {
let res = self.buf[self.at];
Some(if res == b'\r' { b'\n' } else { res })
} else {
None
}
}
pub fn skip_whitespace(&mut self) {
while let Some(b) = self.peek() {
if !b.is_ascii_whitespace() {
return;
}
self.get();
}
}
pub fn next_token(&mut self) -> Option<Vec<u8>> {
self.skip_whitespace();
let mut res = Vec::new();
while let Some(c) = self.get() {
if c.is_ascii_whitespace() {
break;
}
res.push(c);
}
if res.is_empty() { None } else { Some(res) }
}
pub fn is_exhausted(&mut self) -> bool {
self.peek().is_none()
}
pub fn is_empty(&mut self) -> bool {
self.skip_whitespace();
self.is_exhausted()
}
pub fn read<T: Readable>(&mut self) -> T {
T::read(self)
}
pub fn read_vec<T: Readable>(&mut self, size: usize) -> Vec<T> {
let mut res = Vec::with_capacity(size);
for _ in 0..size {
res.push(self.read());
}
res
}
pub fn read_char(&mut self) -> u8 {
self.skip_whitespace();
self.get().unwrap()
}
read_impl!(u32, read_unsigned, read_unsigned_vec);
read_impl!(u64, read_u64, read_u64_vec);
read_impl!(usize, read_size, read_size_vec, read_size_pair_vec);
read_impl!(i32, read_int, read_int_vec, read_int_pair_vec);
read_impl!(i64, read_long, read_long_vec, read_long_pair_vec);
read_impl!(i128, read_i128, read_i128_vec);
fn refill_buffer(&mut self) -> bool {
if self.at == self.buf_read {
self.at = 0;
self.buf_read = match &mut self.input {
InputSource::Stdin(stdin) => stdin.read(&mut self.buf).unwrap(),
InputSource::File(file) => file.read(&mut self.buf).unwrap(),
InputSource::Delegate(reader) => reader.read(&mut self.buf).unwrap(),
InputSource::Slice => 0,
};
self.buf_read != 0
} else {
true
}
}
pub fn is_eol(&self) -> bool {
self.eol
}
}
pub trait Readable {
fn read(input: &mut Input) -> Self;
}
impl Readable for u8 {
fn read(input: &mut Input) -> Self {
input.read_char()
}
}
impl<T: Readable> Readable for Vec<T> {
fn read(input: &mut Input) -> Self {
let size = input.read();
input.read_vec(size)
}
}
impl<T: Readable, const SIZE: usize> Readable for [T; SIZE] {
fn read(input: &mut Input) -> Self {
unsafe {
let mut res = MaybeUninit::<[T; SIZE]>::uninit();
for i in 0..SIZE {
let ptr: *mut T = (*res.as_mut_ptr()).as_mut_ptr();
ptr.add(i).write(input.read::<T>());
}
res.assume_init()
}
}
}
macro_rules! read_integer {
($($t:ident)+) => {
$(impl Readable for $t { fn read(input : & mut Input) -> Self { input
.skip_whitespace(); let mut c = input.get().unwrap(); let sgn = match c { b'-' =>
{ c = input.get().unwrap(); true } b'+' => { c = input.get().unwrap(); false } _
=> false, }; let mut res = 0; loop { assert!(c.is_ascii_digit()); res *= 10; let
d = (c - b'0') as $t; if sgn { res -= d; } else { res += d; } match input.get() {
None => break, Some(ch) => { if ch.is_ascii_whitespace() { break; } else { c =
ch; } } } } res } })+
};
}
read_integer!(i8 i16 i32 i64 i128 isize u16 u32 u64 u128 usize);
macro_rules! tuple_readable {
($($name:ident)+) => {
impl <$($name : Readable),+> Readable for ($($name,)+) { fn read(input : & mut
Input) -> Self { ($($name ::read(input),)+) } }
};
}
tuple_readable! {
T
}
tuple_readable! {
T U
}
tuple_readable! {
T U V
}
tuple_readable! {
T U V X
}
tuple_readable! {
T U V X Y
}
tuple_readable! {
T U V X Y Z
}
tuple_readable! {
T U V X Y Z A
}
tuple_readable! {
T U V X Y Z A B
}
tuple_readable! {
T U V X Y Z A B C
}
tuple_readable! {
T U V X Y Z A B C D
}
tuple_readable! {
T U V X Y Z A B C D E
}
tuple_readable! {
T U V X Y Z A B C D E F
}
}
pub mod output {
use std::cmp::Reverse;
use std::fs::File;
use std::io::{Stdout, Write};
#[derive(Copy, Clone)]
pub enum BoolOutput {
YesNo,
YesNoCaps,
PossibleImpossible,
Custom(&'static str, &'static str),
}
impl BoolOutput {
pub fn output(&self, output: &mut Output, val: bool) {
(if val { self.yes() } else { self.no() }).write(output);
}
fn yes(&self) -> &str {
match self {
BoolOutput::YesNo => "Yes",
BoolOutput::YesNoCaps => "YES",
BoolOutput::PossibleImpossible => "Possible",
BoolOutput::Custom(yes, _) => yes,
}
}
fn no(&self) -> &str {
match self {
BoolOutput::YesNo => "No",
BoolOutput::YesNoCaps => "NO",
BoolOutput::PossibleImpossible => "Impossible",
BoolOutput::Custom(_, no) => no,
}
}
}
enum OutputDest<'s> {
Stdout(Stdout),
File(File),
Buf(&'s mut Vec<u8>),
Delegate(Box<dyn Write + 's>),
}
pub struct Output<'s> {
output: OutputDest<'s>,
buf: Vec<u8>,
at: usize,
bool_output: BoolOutput,
precision: Option<usize>,
separator: u8,
}
impl<'s> Output<'s> {
pub fn buf(buf: &'s mut Vec<u8>) -> Self {
Self::new(OutputDest::Buf(buf))
}
pub fn delegate(delegate: impl Write + 'static) -> Self {
Self::new(OutputDest::Delegate(Box::new(delegate)))
}
fn new(output: OutputDest<'s>) -> Self {
Self {
output,
buf: vec![0; Self::DEFAULT_BUF_SIZE],
at: 0,
bool_output: BoolOutput::YesNoCaps,
precision: None,
separator: b' ',
}
}
}
impl Output<'static> {
pub fn stdout() -> Self {
Self::new(OutputDest::Stdout(std::io::stdout()))
}
pub fn file(file: File) -> Self {
Self::new(OutputDest::File(file))
}
}
impl Output<'_> {
const DEFAULT_BUF_SIZE: usize = 4096;
pub fn flush(&mut self) {
if self.at != 0 {
match &mut self.output {
OutputDest::Stdout(stdout) => {
stdout.write_all(&self.buf[..self.at]).unwrap();
stdout.flush().unwrap();
}
OutputDest::File(file) => {
file.write_all(&self.buf[..self.at]).unwrap();
file.flush().unwrap();
}
OutputDest::Buf(buf) => buf.extend_from_slice(&self.buf[..self.at]),
OutputDest::Delegate(delegate) => {
delegate.write_all(&self.buf[..self.at]).unwrap();
delegate.flush().unwrap();
}
}
self.at = 0;
}
}
pub fn print<T: Writable>(&mut self, s: T) {
s.write(self);
}
pub fn print_line<T: Writable>(&mut self, s: T) {
self.print(s);
self.put(b'\n');
}
pub fn put(&mut self, b: u8) {
self.buf[self.at] = b;
self.at += 1;
if self.at == self.buf.len() {
self.flush();
}
}
pub fn print_per_line<T: Writable>(&mut self, arg: &[T]) {
self.print_per_line_iter(arg.iter());
}
pub fn print_iter<T: Writable, I: Iterator<Item = T>>(&mut self, iter: I) {
let mut first = true;
for e in iter {
if first {
first = false;
} else {
self.put(self.separator);
}
e.write(self);
}
}
pub fn print_line_iter<T: Writable, I: Iterator<Item = T>>(&mut self, iter: I) {
self.print_iter(iter);
self.put(b'\n');
}
pub fn print_per_line_iter<T: Writable, I: Iterator<Item = T>>(&mut self, iter: I) {
for e in iter {
e.write(self);
self.put(b'\n');
}
}
pub fn set_bool_output(&mut self, bool_output: BoolOutput) {
self.bool_output = bool_output;
}
pub fn set_precision(&mut self, precision: usize) {
self.precision = Some(precision);
}
pub fn reset_precision(&mut self) {
self.precision = None;
}
pub fn get_precision(&self) -> Option<usize> {
self.precision
}
pub fn separator(&self) -> u8 {
self.separator
}
pub fn set_separator(&mut self, separator: u8) {
self.separator = separator;
}
}
impl Write for Output<'_> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let mut start = 0usize;
let mut rem = buf.len();
while rem > 0 {
let len = (self.buf.len() - self.at).min(rem);
self.buf[self.at..self.at + len].copy_from_slice(&buf[start..start + len]);
self.at += len;
if self.at == self.buf.len() {
self.flush();
}
start += len;
rem -= len;
}
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
self.flush();
Ok(())
}
}
pub trait Writable {
fn write(&self, output: &mut Output);
}
impl Writable for &str {
fn write(&self, output: &mut Output) {
output.write_all(self.as_bytes()).unwrap();
}
}
impl Writable for String {
fn write(&self, output: &mut Output) {
output.write_all(self.as_bytes()).unwrap();
}
}
impl Writable for char {
fn write(&self, output: &mut Output) {
output.put(*self as u8);
}
}
impl Writable for u8 {
fn write(&self, output: &mut Output) {
output.put(*self);
}
}
impl<T: Writable> Writable for [T] {
fn write(&self, output: &mut Output) {
output.print_iter(self.iter());
}
}
impl<T: Writable, const N: usize> Writable for [T; N] {
fn write(&self, output: &mut Output) {
output.print_iter(self.iter());
}
}
impl<T: Writable + ?Sized> Writable for &T {
fn write(&self, output: &mut Output) {
T::write(self, output)
}
}
impl<T: Writable> Writable for Vec<T> {
fn write(&self, output: &mut Output) {
self.as_slice().write(output);
}
}
impl Writable for () {
fn write(&self, _output: &mut Output) {}
}
macro_rules! write_to_string {
($($t:ident)+) => {
$(impl Writable for $t { fn write(& self, output : & mut Output) { self
.to_string().write(output); } })+
};
}
write_to_string!(u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
macro_rules! tuple_writable {
($name0:ident $($name:ident : $id:tt)*) => {
impl <$name0 : Writable, $($name : Writable,)*> Writable for ($name0, $($name,)*)
{ fn write(& self, out : & mut Output) { self.0.write(out); $(out.put(out
.separator); self.$id .write(out);)* } }
};
}
tuple_writable! {
T
}
tuple_writable! {
T U : 1
}
tuple_writable! {
T U : 1 V : 2
}
tuple_writable! {
T U : 1 V : 2 X : 3
}
tuple_writable! {
T U : 1 V : 2 X : 3 Y : 4
}
tuple_writable! {
T U : 1 V : 2 X : 3 Y : 4 Z : 5
}
tuple_writable! {
T U : 1 V : 2 X : 3 Y : 4 Z : 5 A : 6
}
tuple_writable! {
T U : 1 V : 2 X : 3 Y : 4 Z : 5 A : 6 B : 7
}
tuple_writable! {
T U : 1 V : 2 X : 3 Y : 4 Z : 5 A : 6 B : 7 C : 8
}
impl<T: Writable> Writable for Option<T> {
fn write(&self, output: &mut Output) {
match self {
None => (-1).write(output),
Some(t) => t.write(output),
}
}
}
impl Writable for bool {
fn write(&self, output: &mut Output) {
let bool_output = output.bool_output;
bool_output.output(output, *self)
}
}
impl<T: Writable> Writable for Reverse<T> {
fn write(&self, output: &mut Output) {
self.0.write(output);
}
}
}
}
pub mod misc {
pub mod lazy_lock {
use std::cell::UnsafeCell;
use std::mem::ManuallyDrop;
use std::ops::Deref;
use std::sync::Once;
union Data<T, F> {
value: ManuallyDrop<T>,
f: ManuallyDrop<F>,
}
pub struct LazyLock<T, F = fn() -> T> {
once: Once,
data: UnsafeCell<Data<T, F>>,
}
impl<T, F: FnOnce() -> T> LazyLock<T, F> {
#[inline]
pub const fn new(f: F) -> LazyLock<T, F> {
LazyLock {
once: Once::new(),
data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }),
}
}
#[inline]
pub fn force(this: &LazyLock<T, F>) -> &T {
this.once
.call_once(|| {
let data = unsafe { &mut *this.data.get() };
let f = unsafe { ManuallyDrop::take(&mut data.f) };
let value = f();
data.value = ManuallyDrop::new(value);
});
unsafe { &(*this.data.get()).value }
}
}
impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
LazyLock::force(self)
}
}
unsafe impl<T: Sync + Send, F: Send> Sync for LazyLock<T, F> {}
}
pub mod test_type {
pub enum TestType {
Single,
MultiNumber,
MultiEof,
}
pub enum TaskType {
Classic,
Interactive,
}
}
}
pub mod numbers {
pub mod num_traits {
pub mod algebra {
use crate::algo_lib::numbers::num_traits::invertible::Invertible;
use std::ops::{
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
};
pub trait Zero {
fn zero() -> Self;
}
pub trait One {
fn one() -> Self;
}
pub trait AdditionMonoid: Add<Output = Self> + AddAssign + Zero + Eq + Sized {}
impl<T: Add<Output = Self> + AddAssign + Zero + Eq> AdditionMonoid for T {}
pub trait AdditionMonoidWithSub: AdditionMonoid + Sub<Output = Self> + SubAssign {}
impl<T: AdditionMonoid + Sub<Output = Self> + SubAssign> AdditionMonoidWithSub for T {}
pub trait AdditionGroup: AdditionMonoidWithSub + Neg<Output = Self> {}
impl<T: AdditionMonoidWithSub + Neg<Output = Self>> AdditionGroup for T {}
pub trait MultiplicationMonoid: Mul<Output = Self> + MulAssign + One + Eq + Sized {}
impl<T: Mul<Output = Self> + MulAssign + One + Eq> MultiplicationMonoid for T {}
pub trait IntegerMultiplicationMonoid: MultiplicationMonoid + Div<
Output = Self,
> + Rem<Output = Self> + DivAssign + RemAssign {}
impl<
T: MultiplicationMonoid + Div<Output = Self> + Rem<Output = Self> + DivAssign
+ RemAssign,
> IntegerMultiplicationMonoid for T {}
pub trait MultiplicationGroup: MultiplicationMonoid + Div<
Output = Self,
> + DivAssign + Invertible<Output = Self> {}
impl<
T: MultiplicationMonoid + Div<Output = Self> + DivAssign + Invertible<Output = Self>,
> MultiplicationGroup for T {}
pub trait SemiRing: AdditionMonoid + MultiplicationMonoid {}
impl<T: AdditionMonoid + MultiplicationMonoid> SemiRing for T {}
pub trait SemiRingWithSub: AdditionMonoidWithSub + SemiRing {}
impl<T: AdditionMonoidWithSub + SemiRing> SemiRingWithSub for T {}
pub trait Ring: SemiRing + AdditionGroup {}
impl<T: SemiRing + AdditionGroup> Ring for T {}
pub trait IntegerSemiRing: SemiRing + IntegerMultiplicationMonoid {}
impl<T: SemiRing + IntegerMultiplicationMonoid> IntegerSemiRing for T {}
pub trait IntegerSemiRingWithSub: SemiRingWithSub + IntegerSemiRing {}
impl<T: SemiRingWithSub + IntegerSemiRing> IntegerSemiRingWithSub for T {}
pub trait IntegerRing: IntegerSemiRing + Ring {}
impl<T: IntegerSemiRing + Ring> IntegerRing for T {}
pub trait Field: Ring + MultiplicationGroup {}
impl<T: Ring + MultiplicationGroup> Field for T {}
macro_rules! zero_one_integer_impl {
($($t:ident)+) => {
$(impl Zero for $t { fn zero() -> Self { 0 } } impl One for $t { fn one() -> Self
{ 1 } })+
};
}
zero_one_integer_impl!(i128 i64 i32 i16 i8 isize u128 u64 u32 u16 u8 usize);
}
pub mod invertible {
pub trait Invertible {
type Output;
fn inv(&self) -> Option<Self::Output>;
}
}
}
}
}
Submission Info
| Submission Time |
|
| Task |
D - Moving Pieces on Graph |
| User |
Egor |
| Language |
Rust (rustc 1.70.0) |
| Score |
700 |
| Code Size |
50505 Byte |
| Status |
AC |
| Exec Time |
93 ms |
| Memory |
36256 KiB |
Judge Result
| Set Name |
Sample |
All |
| Score / Max Score |
0 / 0 |
700 / 700 |
| Status |
|
|
| Set Name |
Test Cases |
| Sample |
00_sample_00.txt, 00_sample_01.txt, 00_sample_02.txt |
| All |
00_sample_00.txt, 00_sample_01.txt, 00_sample_02.txt, 01_handmade_00.txt, 01_handmade_01.txt, 01_handmade_02.txt, 01_handmade_03.txt, 01_handmade_04.txt, 01_handmade_05.txt, 01_handmade_06.txt, 02_line_00.txt, 02_line_01.txt, 02_line_02.txt, 03_line_like_00.txt, 03_line_like_01.txt, 03_line_like_02.txt, 03_line_like_03.txt, 03_line_like_04.txt, 03_line_like_05.txt, 03_line_like_06.txt, 03_line_like_07.txt, 03_line_like_08.txt, 03_line_like_09.txt, 03_line_like_10.txt, 03_line_like_11.txt, 03_line_like_12.txt, 03_line_like_13.txt, 03_line_like_14.txt, 03_line_like_15.txt, 03_line_like_16.txt, 03_line_like_17.txt, 03_line_like_18.txt, 03_line_like_19.txt, 03_line_like_20.txt, 03_line_like_21.txt, 03_line_like_22.txt, 03_line_like_23.txt, 04_circle_like_00.txt, 04_circle_like_01.txt, 04_circle_like_02.txt, 04_circle_like_03.txt, 04_circle_like_04.txt, 04_circle_like_05.txt, 04_circle_like_06.txt, 04_circle_like_07.txt, 04_circle_like_08.txt, 04_circle_like_09.txt, 05_dense_00.txt, 05_dense_01.txt, 05_dense_02.txt, 06_random_00.txt, 06_random_01.txt, 06_random_02.txt, 06_random_03.txt, 06_random_04.txt, 06_random_05.txt, 06_random_06.txt, 06_random_07.txt, 06_random_08.txt, 06_random_09.txt, 07_uni_00.txt, 07_uni_01.txt, 07_uni_02.txt, 07_uni_03.txt |
| Case Name |
Status |
Exec Time |
Memory |
| 00_sample_00.txt |
AC |
1 ms |
2012 KiB |
| 00_sample_01.txt |
AC |
1 ms |
1940 KiB |
| 00_sample_02.txt |
AC |
1 ms |
1808 KiB |
| 01_handmade_00.txt |
AC |
1 ms |
2004 KiB |
| 01_handmade_01.txt |
AC |
0 ms |
1872 KiB |
| 01_handmade_02.txt |
AC |
1 ms |
2076 KiB |
| 01_handmade_03.txt |
AC |
0 ms |
1936 KiB |
| 01_handmade_04.txt |
AC |
1 ms |
2148 KiB |
| 01_handmade_05.txt |
AC |
64 ms |
33140 KiB |
| 01_handmade_06.txt |
AC |
75 ms |
35708 KiB |
| 02_line_00.txt |
AC |
3 ms |
3432 KiB |
| 02_line_01.txt |
AC |
77 ms |
35652 KiB |
| 02_line_02.txt |
AC |
93 ms |
35504 KiB |
| 03_line_like_00.txt |
AC |
88 ms |
35644 KiB |
| 03_line_like_01.txt |
AC |
82 ms |
35640 KiB |
| 03_line_like_02.txt |
AC |
37 ms |
14572 KiB |
| 03_line_like_03.txt |
AC |
51 ms |
21168 KiB |
| 03_line_like_04.txt |
AC |
25 ms |
13540 KiB |
| 03_line_like_05.txt |
AC |
42 ms |
19628 KiB |
| 03_line_like_06.txt |
AC |
27 ms |
14424 KiB |
| 03_line_like_07.txt |
AC |
68 ms |
27452 KiB |
| 03_line_like_08.txt |
AC |
86 ms |
36256 KiB |
| 03_line_like_09.txt |
AC |
52 ms |
30192 KiB |
| 03_line_like_10.txt |
AC |
26 ms |
12372 KiB |
| 03_line_like_11.txt |
AC |
65 ms |
27344 KiB |
| 03_line_like_12.txt |
AC |
51 ms |
21304 KiB |
| 03_line_like_13.txt |
AC |
66 ms |
35748 KiB |
| 03_line_like_14.txt |
AC |
65 ms |
33028 KiB |
| 03_line_like_15.txt |
AC |
27 ms |
14376 KiB |
| 03_line_like_16.txt |
AC |
57 ms |
23656 KiB |
| 03_line_like_17.txt |
AC |
82 ms |
35756 KiB |
| 03_line_like_18.txt |
AC |
1 ms |
2228 KiB |
| 03_line_like_19.txt |
AC |
1 ms |
2112 KiB |
| 03_line_like_20.txt |
AC |
0 ms |
2076 KiB |
| 03_line_like_21.txt |
AC |
1 ms |
2072 KiB |
| 03_line_like_22.txt |
AC |
1 ms |
2028 KiB |
| 03_line_like_23.txt |
AC |
1 ms |
2300 KiB |
| 04_circle_like_00.txt |
AC |
85 ms |
35608 KiB |
| 04_circle_like_01.txt |
AC |
76 ms |
35548 KiB |
| 04_circle_like_02.txt |
AC |
87 ms |
35480 KiB |
| 04_circle_like_03.txt |
AC |
79 ms |
35688 KiB |
| 04_circle_like_04.txt |
AC |
75 ms |
35640 KiB |
| 04_circle_like_05.txt |
AC |
11 ms |
9000 KiB |
| 04_circle_like_06.txt |
AC |
11 ms |
9000 KiB |
| 04_circle_like_07.txt |
AC |
11 ms |
8920 KiB |
| 04_circle_like_08.txt |
AC |
11 ms |
9040 KiB |
| 04_circle_like_09.txt |
AC |
11 ms |
8944 KiB |
| 05_dense_00.txt |
AC |
14 ms |
7908 KiB |
| 05_dense_01.txt |
AC |
3 ms |
2760 KiB |
| 05_dense_02.txt |
AC |
7 ms |
5020 KiB |
| 06_random_00.txt |
AC |
27 ms |
11224 KiB |
| 06_random_01.txt |
AC |
28 ms |
11504 KiB |
| 06_random_02.txt |
AC |
44 ms |
18240 KiB |
| 06_random_03.txt |
AC |
37 ms |
14604 KiB |
| 06_random_04.txt |
AC |
31 ms |
11668 KiB |
| 06_random_05.txt |
AC |
46 ms |
18416 KiB |
| 06_random_06.txt |
AC |
31 ms |
11828 KiB |
| 06_random_07.txt |
AC |
44 ms |
17592 KiB |
| 06_random_08.txt |
AC |
44 ms |
17964 KiB |
| 06_random_09.txt |
AC |
48 ms |
19672 KiB |
| 07_uni_00.txt |
AC |
20 ms |
12596 KiB |
| 07_uni_01.txt |
AC |
7 ms |
5684 KiB |
| 07_uni_02.txt |
AC |
37 ms |
19832 KiB |
| 07_uni_03.txt |
AC |
37 ms |
19748 KiB |