結果
| 問題 |
No.2296 Union Path Query (Hard)
|
| コンテスト | |
| ユーザー |
akakimidori
|
| 提出日時 | 2023-04-23 04:38:06 |
| 言語 | Rust (1.83.0 + proconio) |
| 結果 |
AC
|
| 実行時間 | 1,237 ms / 7,000 ms |
| コード長 | 4,683 bytes |
| コンパイル時間 | 13,813 ms |
| コンパイル使用メモリ | 398,636 KB |
| 実行使用メモリ | 102,580 KB |
| 最終ジャッジ日時 | 2024-11-23 04:57:01 |
| 合計ジャッジ時間 | 46,796 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 4 |
| other | AC * 45 |
ソースコード
use std::io::Write;
fn main() {
let (n, mut x, _, query) = read();
let out = std::io::stdout();
let mut out = std::io::BufWriter::new(out.lock());
let mut solver = Solver::new(n);
for (op, v, w) in query {
if op == 1 {
solver.unite(x, v, w as i64);
} else if op == 2 {
let ans = solver.dist(v, w).unwrap_or(-1);
writeln!(out, "{}", ans).ok();
if ans >= 0 {
x += ans as usize;
}
} else if op == 3 {
writeln!(out, "{}", solver.diameter(v)).ok();
} else {
x += v;
}
x %= n;
}
}
fn read() -> (usize, usize, usize, Vec<(u8, usize, usize)>) {
use std::io::*;
let mut s = String::new();
std::io::stdin().read_to_string(&mut s).unwrap();
let mut it = s.trim().split_whitespace().flat_map(|s| s.parse::<usize>());
let mut next = || it.next().unwrap();
let n = next();
let x = next();
let q = next();
let mut ask = vec![(0, 0, 0); q];
for ask in ask.iter_mut() {
ask.0 = next() as u8;
ask.1 = next();
if ask.0 <= 2 {
ask.2 = next();
}
}
(n, x, q, ask)
}
struct Solver {
dsu: Vec<i32>,
tree: Vec<Vec<(usize, i64)>>,
table: Vec<Vec<(usize, i64)>>,
rad: Vec<(i64, usize, usize)>,
depth: Vec<(usize, i64)>,
}
impl Solver {
fn new(n: usize) -> Self {
let ini = (0..n).map(|x| (x, 0)).collect::<Vec<_>>();
let rad = (0..n).map(|x| (0, x, x)).collect::<Vec<_>>();
let k = n.next_power_of_two().trailing_zeros();
Self {
dsu: vec![-1; n],
tree: vec![vec![]; n],
table: vec![ini; k as usize + 1],
rad: rad,
depth: vec![(0, 0); n],
}
}
fn root(&mut self, x: usize) -> usize {
if self.dsu[x] < 0 {
x
} else {
self.dsu[x] = self.root(self.dsu[x] as usize) as i32;
self.dsu[x] as usize
}
}
fn same(&mut self, x: usize, y: usize) -> bool {
self.root(x) == self.root(y)
}
fn dist(&mut self, mut x: usize, mut y: usize) -> Option<i64> {
if !self.same(x, y) {
return None;
}
if self.depth[x].0 < self.depth[y].0 {
std::mem::swap(&mut x, &mut y);
}
let d = self.depth[x].0 - self.depth[y].0;
let mut ans = 0;
for (i, table) in self.table.iter().enumerate() {
if d >> i & 1 == 1 {
ans += table[x].1;
x = table[x].0;
}
}
if x == y {
return Some(ans);
}
for table in self.table.iter().rev() {
if table[x].0 != table[y].0 {
ans += table[x].1 + table[y].1;
x = table[x].0;
y = table[y].0;
}
}
Some(ans + self.table[0][x].1 + self.table[0][y].1)
}
fn diameter(&mut self, x: usize) -> i64 {
let r = self.root(x);
self.rad[r].0
}
fn unite(&mut self, x: usize, y: usize, w: i64) {
let a = self.root(x);
let b = self.root(y);
assert!(a != b);
self.tree[x].push((y, w));
self.tree[y].push((x, w));
let (p, c) = if self.dsu[a] <= self.dsu[b] {
self.dsu[a] += self.dsu[b];
self.dsu[b] = a as i32;
(x, y)
} else {
self.dsu[b] += self.dsu[a];
self.dsu[a] = b as i32;
(y, x)
};
let mut topo = vec![(c, p, w)];
for i in 0.. {
if i >= topo.len() {
break;
}
let (v, p, w) = topo[i];
let up = self.depth[p];
self.depth[v] = (up.0 + 1, up.1 + w);
self.table[0][v] = (p, w);
for &(u, w) in self.tree[v].iter().filter(|e| e.0 != p) {
topo.push((u, v, w));
}
}
for i in 1..self.table.len() {
let pre = std::mem::take(&mut self.table[i - 1]);
let table = &mut self.table[i];
for &(v, _, _) in topo.iter() {
let a = pre[v];
let b = pre[a.0];
table[v] = (b.0, a.1 + b.1)
}
self.table[i - 1] = pre;
}
let da = self.rad[a];
let db = self.rad[b];
let mut res = std::cmp::max(da, db);
for &a in [da.1, da.2].iter() {
for &b in [db.1, db.2].iter() {
res = res.max((self.dist(a, b).unwrap(), a, b));
}
}
let r = self.root(a);
self.rad[r] = res;
}
}
akakimidori