結果
| 問題 | No.1787 Do Use Dynamic Tree |
| コンテスト | |
| ユーザー |
akakimidori
|
| 提出日時 | 2026-03-22 09:28:06 |
| 言語 | Rust (1.93.0 + proconio + num + itertools) |
| 結果 |
AC
|
| 実行時間 | 1,132 ms / 10,000 ms |
| コード長 | 20,150 bytes |
| 記録 | |
| コンパイル時間 | 14,473 ms |
| コンパイル使用メモリ | 222,660 KB |
| 実行使用メモリ | 80,696 KB |
| 最終ジャッジ日時 | 2026-03-22 09:28:34 |
| 合計ジャッジ時間 | 13,060 ms |
|
ジャッジサーバーID (参考情報) |
judge3_0 / judge2_0 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 38 |
コンパイルメッセージ
warning: unused variable: `e`
--> src/main.rs:38:40
|
38 | fn add_edge(&self, p: &Self::Path, e: &Self::Edge) -> Self::Point {
| ^ help: if this is intentional, prefix it with an underscore: `_e`
|
= note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default
warning: unused variable: `e`
--> src/main.rs:47:56
|
47 | fn compress(&self, p: &Self::Path, c: &Self::Path, e: &Self::Edge) -> Self::Path {
| ^ help: if this is intentional, prefix it with an underscore: `_e`
ソースコード
fn main() {
let (e, ask) = read();
let n = e.len() + 1;
let mut val = (1..=(n as i32)).collect::<Vec<_>>();
let p = val.iter().enumerate().map(|p| (*p.1, p.0 as i32)).collect::<Vec<_>>();
let mut solver = RerootingDP::new(
R,
p,
e.into_iter().map(|e| (e.0, e.1, ())).collect::<Vec<_>>(),
);
let mut ans = vec![0; ask.len()];
let mut pre = 0;
for (ans, (u, v)) in ans.iter_mut().zip(ask) {
let u = (u + pre) % n;
let v = (v + pre) % n;
val.swap(u, v);
solver.set_vertex(u, (val[u], u as i32));
solver.set_vertex(v, (val[v], v as i32));
let p = solver.find(u);
*ans = p.2 + 1;
pre = *ans as usize;
}
use util::*;
println!("{}", ans.iter().join("\n"));
}
struct R;
impl TreeDP for R {
type Vertex = (i32, i32);
type Edge = ();
// パスの始点、繋がってるなら次の頂点、端
type Path = (i32, i32, i32);
// パスの始点、終端
type Point = (i32, i32);
fn vertex(&self, v: &Self::Vertex) -> Self::Path {
(v.0, 0, v.1)
}
fn add_edge(&self, p: &Self::Path, e: &Self::Edge) -> Self::Point {
(p.0, p.2)
}
fn rake(&self, a: &Self::Point, b: &Self::Point) -> Self::Point {
std::cmp::max(*a, *b)
}
fn add_vertex(&self, p: &Self::Point, v: &Self::Vertex) -> Self::Path {
(v.0, p.0, p.1)
}
fn compress(&self, p: &Self::Path, c: &Self::Path, e: &Self::Edge) -> Self::Path {
if p.1 >= 0 && c.0 > p.1 {
(p.0, c.1, c.2)
} else {
(p.0, -1, p.2)
}
}
}
fn read() -> (Vec<(usize, usize)>, Vec<(usize, usize)>) {
let mut s = String::new();
use std::io::*;
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 e = (1..n)
.map(|_| {
let a = next() - 1;
let b = next() - 1;
(a, b)
})
.collect();
let q = next();
let ask = (0..q)
.map(|_| {
let a = next() - 1;
let b = next() - 1;
(a, b)
})
.collect();
(e, ask)
}
pub trait TreeDP {
type Vertex: Clone;
type Edge: Clone;
type Path: Clone;
type Point: Clone;
fn vertex(&self, v: &Self::Vertex) -> Self::Path;
fn add_edge(&self, p: &Self::Path, e: &Self::Edge) -> Self::Point;
fn rake(&self, a: &Self::Point, b: &Self::Point) -> Self::Point;
fn add_vertex(&self, p: &Self::Point, v: &Self::Vertex) -> Self::Path;
fn compress(&self, p: &Self::Path, c: &Self::Path, e: &Self::Edge) -> Self::Path;
}
pub struct RerootingDP<R, V, E, A, B> {
op: R,
v: Vec<V>,
e: Vec<E>,
sum: Vec<Union<(A, A), B>>,
stt: StaticTopTree,
}
impl<R> RerootingDP<R, R::Vertex, R::Edge, R::Path, R::Point>
where
R: TreeDP,
{
const ROOT: usize = 0;
pub fn new(op: R, v: Vec<R::Vertex>, edge: Vec<(usize, usize, R::Edge)>) -> Self {
assert!(v.len() == edge.len() + 1);
let mut e = vec![];
let mut memo = vec![];
for (a, b, w) in edge {
e.push(w);
memo.push((a, b));
}
let stt = StaticTopTree::new(memo, Self::ROOT);
let sum = vec![Union::V((op.vertex(&v[0]), op.vertex(&v[0]))); stt.label.len()];
let mut res = Self { op, v, e, sum, stt };
for i in 0..res.stt.label.len() {
res.pull(i);
}
res
}
pub fn set_vertex(&mut self, v: usize, w: R::Vertex) {
self.v[v] = w;
self.update(self.stt.vertex[v]);
}
pub fn set_edge(&mut self, e: usize, w: R::Edge) {
self.e[e] = w;
self.update(self.stt.edge[e]);
}
pub fn find(&self, root: usize) -> R::Path {
if root == Self::ROOT {
return self.sum.last().unwrap().get_v().0.clone();
}
// なんか非常に汚い、もっと綺麗に書けないか
let mut pos = self.stt.vertex[root];
let mut memo = vec![];
while let Some(p) = self.stt.node[pos].p.get() {
let l = self.stt.node[p].l.get().unwrap() == pos;
pos = p;
memo.push((p, l));
}
let mut up: Option<(R::Path, R::Edge)> = None;
let mut down: Option<(R::Path, R::Edge)> = None;
let mut point: Option<R::Point> = None;
let mut vertex: Option<R::Vertex> = None;
for &(pos, left) in memo.iter().rev() {
if self.stt.label[pos] == STTLabel::Compress {
let e = &self.e[self.stt.node[pos].e.get().unwrap()];
if left {
let r = self.stt.node[pos].r.get().unwrap();
let r = &self.sum[r].get_v().0;
down = Some(down.map_or((r.clone(), e.clone()), |(a, b)| {
(self.op.compress(r, &a, &b), e.clone())
}));
} else {
let l = self.stt.node[pos].l.get().unwrap();
let l = &self.sum[l].get_v().1;
up = Some(up.map_or((l.clone(), e.clone()), |(a, b)| {
(self.op.compress(l, &a, &b), e.clone())
}));
}
} else if self.stt.label[pos] == STTLabel::AddVertex {
vertex = Some(self.v[self.stt.node[pos].e.get().unwrap()].clone());
let u = up.take().map(|p| self.op.add_edge(&p.0, &p.1));
let d = down.take().map(|p| self.op.add_edge(&p.0, &p.1));
point = match (u, d) {
(Some(a), Some(b)) => Some(self.op.rake(&a, &b)),
(a, b) => a.or(b),
};
} else if self.stt.label[pos] == STTLabel::Rake {
let other = if left {
self.stt.node[pos].r
} else {
self.stt.node[pos].l
}
.get()
.unwrap();
let p = self.sum[other].get_e();
point = Some(point.map_or(p.clone(), |q| self.op.rake(p, &q)));
} else if self.stt.label[pos] == STTLabel::AddEdge {
let e = &self.e[self.stt.node[pos].e.get().unwrap()];
if point.is_some() {
let p = point.take().unwrap();
let v = vertex.take().unwrap();
up = Some((self.op.add_vertex(&p, &v), e.clone()));
} else {
unreachable!()
}
} else {
unreachable!()
}
}
let pos = self.stt.vertex[root];
if self.stt.label[pos] == STTLabel::AddVertex {
let u = up.map(|p| self.op.add_edge(&p.0, &p.1));
let d = down.map(|p| self.op.add_edge(&p.0, &p.1));
let p = match (u, d) {
(Some(a), Some(b)) => Some(self.op.rake(&a, &b)),
(a, b) => a.or(b),
}
.unwrap();
let c = self.sum[self.stt.node[pos].l.get().unwrap()].get_e();
let q = self.op.rake(&p, c);
self.op.add_vertex(&q, &self.v[root])
} else {
let u = up.map(|p| self.op.add_edge(&p.0, &p.1));
let d = down.map(|p| self.op.add_edge(&p.0, &p.1));
let p = match (u, d) {
(Some(a), Some(b)) => Some(self.op.rake(&a, &b)),
(a, b) => a.or(b),
}
.unwrap();
self.op.add_vertex(&p, &self.v[root])
}
}
fn update(&mut self, mut v: usize) {
self.pull(v);
while let Some(p) = self.stt.node[v].p.get() {
v = p;
self.pull(p);
}
}
fn pull(&mut self, v: usize) {
match self.stt.label[v] {
STTLabel::Vertex => {
let u = self.stt.node[v].e.get().unwrap();
let p = self.op.vertex(&self.v[u]);
self.sum[v].set_v((p.clone(), p));
}
STTLabel::AddEdge => {
let l = self.stt.node[v].l.get().unwrap();
let e = self.stt.node[v].e.get().unwrap();
let path = &self.sum[l].get_v().0;
let point = self.op.add_edge(path, &self.e[e]);
self.sum[v].set_e(point);
}
STTLabel::Rake => {
let l = self.stt.node[v].l.get().unwrap();
let r = self.stt.node[v].r.get().unwrap();
let point = self.op.rake(self.sum[l].get_e(), self.sum[r].get_e());
self.sum[v].set_e(point);
}
STTLabel::AddVertex => {
let l = self.stt.node[v].l.get().unwrap();
let u = self.stt.node[v].e.get().unwrap();
let path = self.op.add_vertex(self.sum[l].get_e(), &self.v[u]);
self.sum[v].set_v((path.clone(), path));
}
STTLabel::Compress => {
let l = self.sum[self.stt.node[v].l.get().unwrap()].get_v();
let r = self.sum[self.stt.node[v].r.get().unwrap()].get_v();
let e = self.stt.node[v].e.get().unwrap();
let lr = self.op.compress(&l.0, &r.0, &self.e[e]);
let rl = self.op.compress(&r.1, &l.1, &self.e[e]);
self.sum[v].set_v((lr, rl));
}
}
}
}
pub struct FixRootTreeDP<R, V, E, A, B> {
op: R,
v: Vec<V>,
e: Vec<E>,
sum: Vec<Union<A, B>>,
stt: StaticTopTree,
}
impl<R> FixRootTreeDP<R, R::Vertex, R::Edge, R::Path, R::Point>
where
R: TreeDP,
{
pub fn new(op: R, v: Vec<R::Vertex>, edge: Vec<(usize, usize, R::Edge)>) -> Self {
assert!(v.len() == edge.len() + 1);
let mut e = vec![];
let mut memo = vec![];
for (a, b, w) in edge {
e.push(w);
memo.push((a, b));
}
let stt = StaticTopTree::new(memo, 0);
let sum = vec![Union::V(op.vertex(&v[0])); stt.label.len()];
let mut res = Self { op, v, e, sum, stt };
for i in 0..res.stt.label.len() {
res.pull(i);
}
res
}
pub fn set_vertex(&mut self, v: usize, w: R::Vertex) {
self.v[v] = w;
self.update(self.stt.vertex[v]);
}
pub fn set_edge(&mut self, e: usize, w: R::Edge) {
self.e[e] = w;
self.update(self.stt.edge[e]);
}
pub fn find(&self) -> R::Path {
self.sum.last().unwrap().get_v().clone()
}
fn update(&mut self, mut v: usize) {
self.pull(v);
while let Some(p) = self.stt.node[v].p.get() {
v = p;
self.pull(p);
}
}
fn pull(&mut self, v: usize) {
match self.stt.label[v] {
STTLabel::Vertex => {
let u = self.stt.node[v].e.get().unwrap();
self.sum[v].set_v(self.op.vertex(&self.v[u]));
}
STTLabel::AddEdge => {
let l = self.stt.node[v].l.get().unwrap();
let e = self.stt.node[v].e.get().unwrap();
let path = self.sum[l].get_v();
let point = self.op.add_edge(path, &self.e[e]);
self.sum[v].set_e(point);
}
STTLabel::Rake => {
let l = self.stt.node[v].l.get().unwrap();
let r = self.stt.node[v].r.get().unwrap();
let point = self.op.rake(self.sum[l].get_e(), self.sum[r].get_e());
self.sum[v].set_e(point);
}
STTLabel::AddVertex => {
let l = self.stt.node[v].l.get().unwrap();
let u = self.stt.node[v].e.get().unwrap();
let path = self.op.add_vertex(self.sum[l].get_e(), &self.v[u]);
self.sum[v].set_v(path);
}
STTLabel::Compress => {
let l = self.sum[self.stt.node[v].l.get().unwrap()].get_v();
let r = self.sum[self.stt.node[v].r.get().unwrap()].get_v();
let e = self.stt.node[v].e.get().unwrap();
let path = self.op.compress(l, r, &self.e[e]);
self.sum[v].set_v(path);
}
}
}
}
#[derive(Clone, Debug)]
enum Union<V, E> {
V(V),
E(E),
}
impl<V, E> Union<V, E> {
fn set_v(&mut self, v: V) {
*self = Self::V(v);
}
fn set_e(&mut self, e: E) {
*self = Self::E(e);
}
fn get_v(&self) -> &V {
let Union::V(ref v) = self else {
unreachable!()
};
v
}
fn get_e(&self) -> &E {
let Union::E(ref v) = self else {
unreachable!()
};
v
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum STTLabel {
Vertex,
AddEdge,
Rake,
AddVertex,
Compress,
}
#[derive(Clone, Debug)]
struct STTNode {
p: Pointer,
l: Pointer,
r: Pointer,
e: Pointer,
}
impl STTNode {
fn new(l: Pointer, r: Pointer, e: Pointer) -> Self {
Self {
p: Pointer::null(),
l,
r,
e,
}
}
}
pub struct StaticTopTree {
label: Vec<STTLabel>,
node: Vec<STTNode>,
height: Vec<usize>,
vertex: Vec<usize>,
edge: Vec<usize>,
size: usize,
}
impl StaticTopTree {
pub fn new(edge: Vec<(usize, usize)>, root: usize) -> Self {
let size = edge.len() + 1;
let mut graph = vec![vec![]; size];
for (i, &(a, b)) in edge.iter().enumerate() {
graph[a].push((b, i));
graph[b].push((a, i));
}
let mut topo = vec![root];
let mut parent = vec![(size, size); size];
let mut inv_edge = vec![size; size];
for i in 0..size {
let v = topo[i];
for (u, k) in graph[v].clone() {
graph[u].retain(|p| p.0 != v);
parent[u] = (v, k);
inv_edge[k] = u;
topo.push(u);
}
}
let mut s = vec![1i32; size];
for &v in topo.iter().rev() {
let c = &mut graph[v];
for i in 1..c.len() {
if s[c[i].0] > s[c[0].0] {
c.swap(0, i);
}
}
s[v] += c.iter().map(|e| s[e.0]).sum::<i32>();
}
let mut stt = Self {
label: vec![],
node: vec![],
height: vec![],
vertex: vec![!0; size],
edge: vec![!0; size - 1],
size,
};
let mut id = vec![!0; size];
let mut array = vec![None; 128];
for &v in topo.iter().rev() {
if graph[v].len() <= 1 {
id[v] = stt.append_inner(!0, !0, v, STTLabel::Vertex);
} else {
let mut bit = 0u128;
for &(u, e) in graph[v][1..].iter() {
let mut k = stt.append_inner(id[u], !0, e, STTLabel::AddEdge);
let mut h = stt.height[k];
while let Some(x) = array[h].take() {
bit ^= 1 << h;
k = stt.append_inner(k, x, !0, STTLabel::Rake);
h = stt.height[k];
}
array[h] = Some(k);
bit |= 1 << h;
}
let x = bit.trailing_zeros() as usize;
let mut k = array[x].take().unwrap();
bit ^= 1 << x;
while bit > 0 {
let x = bit.trailing_zeros() as usize;
let u = array[x].take().unwrap();
k = stt.append_inner(k, u, !0, STTLabel::Rake);
bit ^= 1 << x;
}
id[v] = stt.append_inner(k, !0, v, STTLabel::AddVertex);
}
if v == root || graph[parent[v].0][0].0 != v {
let mut stack = vec![(id[v], size)];
let mut pos = v;
while let Some(&(u, k)) = graph[pos].get(0) {
stack.push((id[u], k));
while stack.len() > 1 {
let len = stack.len();
let (b, a) = (stack[len - 2], stack[len - 1]);
if len >= 3 && stt.height[stack[len - 3].0] <= stt.height[a.0] {
let c = stack[len - 3];
stack.truncate(len - 3);
let v = stt.append_inner(c.0, b.0, b.1, STTLabel::Compress);
stack.extend([(v, c.1), a].iter().cloned());
} else if stt.height[b.0] <= stt.height[a.0] {
stack.truncate(len - 2);
let v = stt.append_inner(b.0, a.0, a.1, STTLabel::Compress);
stack.push((v, b.1));
} else {
break;
}
}
pos = u;
}
while stack.len() >= 2 {
let a = stack.pop().unwrap();
let b = stack.pop().unwrap();
let v = stt.append_inner(b.0, a.0, a.1, STTLabel::Compress);
stack.push((v, b.1));
}
id[v] = stack.pop().unwrap().0;
}
}
stt
}
fn append_inner(&mut self, l: usize, r: usize, e: usize, label: STTLabel) -> usize {
let v = self.node.len();
let mut h = 0;
let lp = if let Some(n) = self.node.get_mut(l) {
n.p.set(v);
h = std::cmp::max(h, self.height[l]);
Pointer::new(l)
} else {
Pointer::null()
};
let rp = if let Some(n) = self.node.get_mut(r) {
n.p.set(v);
h = std::cmp::max(h, self.height[r]);
Pointer::new(r)
} else {
Pointer::null()
};
if self.node.get(r).is_some() {
h += 1;
}
let ep = if e < self.size {
if label == STTLabel::Vertex || label == STTLabel::AddVertex {
self.vertex[e] = v;
} else if label == STTLabel::AddEdge || label == STTLabel::Compress {
self.edge[e] = v;
} else {
unreachable!();
}
Pointer::new(e)
} else {
Pointer::null()
};
self.label.push(label);
self.node.push(STTNode::new(lp, rp, ep));
self.height.push(h);
v
}
}
// ---------- begin pointer ----------
#[derive(Clone, Copy)]
pub struct Pointer(u32);
impl Pointer {
pub fn new(v: usize) -> Self {
Self(v as u32)
}
pub fn null() -> Self {
Self(!0)
}
pub fn get(&self) -> Option<usize> {
if self.0 == !0 {
None
} else {
Some(self.0 as usize)
}
}
pub fn is_null(&self) -> bool {
self.get().is_none()
}
pub fn set(&mut self, v: usize) {
self.0 = v as u32
}
}
impl From<usize> for Pointer {
fn from(x: usize) -> Self {
Self::new(x)
}
}
impl Default for Pointer {
fn default() -> Self {
Self::null()
}
}
impl std::fmt::Debug for Pointer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(x) = self.get() {
write!(f, "{}", x)
} else {
write!(f, "null")
}
}
}
// ---------- end pointer ----------
mod util {
pub trait Join {
fn join(self, sep: &str) -> String;
}
impl<T, I> Join for I
where
I: Iterator<Item = T>,
T: std::fmt::Display,
{
fn join(self, sep: &str) -> String {
let mut s = String::new();
use std::fmt::*;
for (i, v) in self.enumerate() {
if i > 0 {
write!(&mut s, "{}", sep).ok();
}
write!(&mut s, "{}", v).ok();
}
s
}
}
}
akakimidori