結果

問題 No.3442 Good Vertex Connectivity
コンテスト
ユーザー 👑 ArcAki
提出日時 2026-02-17 01:44:56
言語 Rust
(1.93.0 + proconio + num + itertools)
コンパイル:
/usr/bin/rustc_custom
実行:
./target/release/main
結果
AC  
実行時間 1,265 ms / 3,000 ms
コード長 8,580 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 13,984 ms
コンパイル使用メモリ 216,868 KB
実行使用メモリ 329,004 KB
最終ジャッジ日時 2026-02-17 01:46:17
合計ジャッジ時間 71,831 ms
ジャッジサーバーID
(参考情報)
judge4 / judge5
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 1
other AC * 69
権限があれば一括ダウンロードができます
コンパイルメッセージ
warning: unused variable: `idx`
   --> src/main.rs:120:31
    |
120 |         while let Some((v, p, idx, entered)) = st.pop() {
    |                               ^^^ help: if this is intentional, prefix it with an underscore: `_idx`
    |
    = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default

warning: variable does not need to be mutable
   --> src/main.rs:169:23
    |
169 |     pub fn lca(&self, mut u: usize, mut v: usize) -> usize {
    |                       ----^
    |                       |
    |                       help: remove this `mut`
    |
    = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default

warning: variable does not need to be mutable
   --> src/main.rs:169:37
    |
169 |     pub fn lca(&self, mut u: usize, mut v: usize) -> usize {
    |                                     ----^
    |                                     |
    |                                     help: remove this `mut`

warning: variable does not need to be mutable
   --> src/main.rs:190:39
    |
190 |     pub fn climb(&self, mut v: usize, mut k: usize) -> usize {
    |                                       ----^
    |                                       |
    |                                       help: remove this `mut`

warning: field `n` is never read
  --> src/main.rs:94:5
   |
93 | pub struct STLCA {
   |            ----- field in this struct
94 |     n: usize,
   |     ^
   |
   = note: `STLCA` has derived impls for the traits `Debug` and `Clone`, but these are intentionally ignored during dead code analysis
   = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default

ソースコード

diff #
raw source code

#[allow(unused_imports)]
use std::{
    cmp::{self, Reverse, Ordering},
    collections::*,
    io::{self, Read},
    mem::swap,
};

#[allow(unused)]
use proconio::{input, marker::*};

pub trait SegtreeMonoid {
    type S: Clone;
    fn identity(&self) -> Self::S;
    fn op(&self, a: &Self::S, b: &Self::S) -> Self::S;
}

pub struct Segtree<M: SegtreeMonoid> {
    n: usize,
    data: Vec<M::S>,
    m: M,
}
impl<M: SegtreeMonoid> Segtree<M> {
    pub fn new(n: usize, m: M) -> Self {
        let n = n.next_power_of_two();
        let e = m.identity();
        let data = vec![e; 2 * n];
        Segtree { n, data, m }
    }
    pub fn set(&mut self, i: usize, x: M::S) {
        let mut p = i + self.n;
        self.data[p] = x;
        while p > 1 {
            p >>= 1;
            self.data[p] = self.m.op(&self.data[p << 1], &self.data[(p << 1) | 1]);
        }
    }
    pub fn prod(&self, l: usize, r: usize) -> M::S {
        let mut p_l = l + self.n;
        let mut p_r = r + self.n;
        let mut res_l = self.m.identity();
        let mut res_r = self.m.identity();
        while p_l < p_r {
            if p_l & 1 == 1 {
                res_l = self.m.op(&res_l, &self.data[p_l]);
                p_l += 1;
            }
            if p_r & 1 == 1 {
                p_r -= 1;
                res_r = self.m.op(&self.data[p_r], &res_r);
            }
            p_l >>= 1;
            p_r >>= 1;
        }
        self.m.op(&res_l, &res_r)
    }
}

/* ===== Sparse Table for RMQ (min) ===== */
#[derive(Clone, Debug)]
pub struct SparseTableMI<T: Ord + Copy> {
    table: Vec<Vec<T>>,
}
impl<T: Ord + Copy> SparseTableMI<T> {
    pub fn build(a: &Vec<T>) -> Self {
        let n = a.len();
        let mut table: Vec<Vec<T>> = Vec::new();
        table.push(a.clone());
        let mut k = 1;
        while (1usize << k) <= n {
            let prev = &table[k - 1];
            let len = n - (1usize << k) + 1;
            let mut cur = Vec::with_capacity(len);
            let w = 1usize << (k - 1);
            for i in 0..len {
                cur.push(prev[i].min(prev[i + w]));
            }
            table.push(cur);
            k += 1;
        }
        Self { table }
    }
    pub fn query(&self, l: usize, r: usize) -> T {
        let s = r - l;
        let k = (usize::BITS - 1 - s.leading_zeros()) as usize;
        let w = 1usize << k;
        self.table[k][l].min(self.table[k][r - w])
    }
}

/* ===== LCA + depth + tin/tout + binary lifting ===== */
#[derive(Clone, Debug)]
pub struct STLCA {
    n: usize,
    first: Vec<usize>,
    rmq: SparseTableMI<(usize, usize)>,
    depth: Vec<usize>,
    up: Vec<Vec<usize>>,
    tin: Vec<usize>,
    tout: Vec<usize>,
}
impl STLCA {
    pub fn new(n: usize, root: usize, g: &Vec<Vec<usize>>) -> Self {
        let lg = 20; // enough for n<=2e5
        let mut depth = vec![0usize; n];
        let mut parent = vec![root; n];

        let mut tin = vec![0usize; n];
        let mut tout = vec![0usize; n];
        let mut timer = 0usize;

        // iterative DFS: also build Euler tour for LCA RMQ
        let mut first = vec![0usize; n];
        let mut euler: Vec<(usize, usize)> = Vec::with_capacity(2 * n);

        // stack: (v, p, next_child_index, entered?)
        let mut st: Vec<(usize, usize, usize, bool)> = Vec::new();
        st.push((root, root, 0, false));

        while let Some((v, p, idx, entered)) = st.pop() {
            if !entered {
                parent[v] = p;
                tin[v] = timer;
                timer += 1;

                first[v] = euler.len();
                euler.push((depth[v], v));

                st.push((v, p, 0, true));
                for &to in g[v].iter().rev() {
                    if to == p {
                        continue;
                    }
                    depth[to] = depth[v] + 1;
                    st.push((to, v, 0, false));
                }
            } else {
                // leaving v: push parent into euler (if exists)
                tout[v] = timer;
                if v != root {
                    euler.push((depth[p], p));
                }
            }
        }

        // Build binary lifting
        let mut up = vec![vec![root; n]; lg];
        up[0] = parent.clone();
        for k in 1..lg {
            for v in 0..n {
                up[k][v] = up[k - 1][up[k - 1][v]];
            }
        }

        let rmq = SparseTableMI::build(&euler);

        STLCA {
            n,
            first,
            rmq,
            depth,
            up,
            tin,
            tout,
        }
    }

    #[inline(always)]
    pub fn lca(&self, mut u: usize, mut v: usize) -> usize {
        let mut fu = self.first[u];
        let mut fv = self.first[v];
        if fu > fv {
            swap(&mut fu, &mut fv);
        }
        self.rmq.query(fu, fv + 1).1
    }

    #[inline(always)]
    pub fn dist(&self, u: usize, v: usize) -> u64 {
        let p = self.lca(u, v);
        (self.depth[u] + self.depth[v] - 2 * self.depth[p]) as u64
    }

    #[inline(always)]
    pub fn is_ancestor(&self, a: usize, b: usize) -> bool {
        self.tin[a] <= self.tin[b] && self.tout[b] <= self.tout[a]
    }

    #[inline(always)]
    pub fn climb(&self, mut v: usize, mut k: usize) -> usize {
        let lg = self.up.len();
        for i in 0..lg {
            if (k >> i) & 1 == 1 {
                v = self.up[i][v];
            }
        }
        v
    }

    // a is ancestor of b, a != b: return the child of a on path to b
    #[inline(always)]
    pub fn child_on_path(&self, a: usize, b: usize) -> usize {
        // lift b up to depth[a]+1
        let da = self.depth[a];
        let db = self.depth[b];
        let k = db - da - 1;
        self.climb(b, k)
    }
}

/* ===== segment monoid for "virtual tree perimeter" ===== */
struct M {
    lca: STLCA,
}
impl SegtreeMonoid for M {
    // (first, last, sum_dist_consecutive)
    type S = (usize, usize, u64);
    fn identity(&self) -> Self::S {
        (!0, !0, 0)
    }
    fn op(&self, a: &Self::S, b: &Self::S) -> Self::S {
        let first = if a.0 == !0 { b.0 } else { a.0 };
        let last = if b.1 == !0 { a.1 } else { b.1 };
        let mut sum = a.2 + b.2;
        if a.1 != !0 && b.0 != !0 {
            sum += self.lca.dist(a.1, b.0);
        }
        (first, last, sum)
    }
}

#[inline(always)]
fn steiner_vertex_count(lca: &STLCA, s: (usize, usize, u64)) -> u64 {
    if s.0 == !0 {
        return 0;
    }
    // edges = (sum_consecutive + dist(last, first)) / 2
    let edges = (s.2 + lca.dist(s.0, s.1)) / 2;
    edges + 1
}

const MULTI: bool = false;

fn solve() {
    input! {
        n: usize,
        e: [(Usize1, Usize1); n-1],
        mut c: [u8; n],
        q: usize,
    }
    let mut g = vec![Vec::<usize>::new(); n];
    for &(u, v) in &e {
        g[u].push(v);
        g[v].push(u);
    }

    let lca = STLCA::new(n, 0, &g);
    let m = M { lca: lca.clone() };
    let mut seg = Segtree::new(n, m);

    // build initial black set on tin-order
    for v in 0..n {
        if c[v] == 1 {
            seg.set(lca.tin[v], (v, v, 0));
        }
    }

    for _ in 0..q {
        input! { t: u8 }
        if t == 1 {
            input! { v: Usize1 }
            if c[v] == 0 {
                c[v] = 1;
                seg.set(lca.tin[v], (v, v, 0));
            } else {
                c[v] = 0;
                seg.set(lca.tin[v], (!0, !0, 0));
            }
        } else {
            input! { x: Usize1, y: Usize1 }
            if x == y {
                // y is on path(v,x) for all v
                let all = seg.prod(0, n);
                println!("{}", steiner_vertex_count(&lca, all));
                continue;
            }
            let p = lca.lca(x, y);
            if p != y {
                // good vertices are inside subtree(y)
                let s = seg.prod(lca.tin[y], lca.tout[y]);
                println!("{}", steiner_vertex_count(&lca, s));
            } else {
                // y is ancestor of x: exclude subtree(child_on_path(y,x))
                let child = lca.child_on_path(y, x);
                let a = seg.prod(0, lca.tin[child]);
                let b = seg.prod(lca.tout[child], n);
                // combine as one set (already in tin-order: [0,tin) then [tout,n))
                let s = seg.m.op(&a, &b);
                println!("{}", steiner_vertex_count(&lca, s));
            }
        }
    }
}

fn main() {
    if MULTI {
        input! { t: usize }
        for _ in 0..t {
            solve();
        }
    } else {
        solve();
    }
}
0