Skip to content

Commit 29090f8

Browse files
authored
Merge pull request #183 from ia7ck/re-rooting-dp
re-rooting dp
2 parents 6557888 + b424b5c commit 29090f8

File tree

3 files changed

+171
-0
lines changed

3 files changed

+171
-0
lines changed

algo/re_rooting_dp/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "re_rooting_dp"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dev-dependencies]
9+
proconio = {version = "0.4.5", features = ["derive"] }
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// problem: https://judge.yosupo.jp/problem/tree_path_composite_sum
2+
use proconio::input;
3+
use re_rooting_dp::re_rooting_dp;
4+
5+
fn main() {
6+
input! {
7+
n: usize,
8+
a: [u64; n],
9+
edges: [(usize, usize, u64, u64); n - 1],
10+
};
11+
12+
const M: u64 = 998244353;
13+
14+
let edges = edges
15+
.into_iter()
16+
.map(|(u, v, b, c)| (u, v, E { b, c }))
17+
.collect::<Vec<_>>();
18+
19+
let ans = re_rooting_dp(
20+
n,
21+
&edges,
22+
|i| V { val: a[i], size: 1 },
23+
|p, ch, e| {
24+
// Σ_j e.b * P(ch, j) + e.c
25+
// = e.c * ch.size + e.b * Σ_j P(ch, j)
26+
27+
V {
28+
val: (p.val + e.c * ch.size % M + e.b * ch.val % M) % M,
29+
size: p.size + ch.size,
30+
}
31+
},
32+
);
33+
34+
let ans = ans
35+
.iter()
36+
.map(|v| v.val.to_string())
37+
.collect::<Vec<_>>()
38+
.join(" ");
39+
println!("{}", ans);
40+
}
41+
42+
#[derive(Debug)]
43+
struct E {
44+
b: u64,
45+
c: u64,
46+
}
47+
48+
#[derive(Debug, Clone)]
49+
struct V {
50+
// i: usize,
51+
val: u64, // Σ P(i, j)
52+
size: u64, // 部分木のサイズ
53+
}

algo/re_rooting_dp/src/lib.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/// 全方位木DP
2+
///
3+
/// `fold(p, ch, e)` は親頂点 `p` に子の頂点 `ch` を辺 `e` 含めてマージした結果を返すよう実装する
4+
///
5+
/// ```no_run
6+
/// // 各頂点から最も遠い頂点までの距離を求める例
7+
///
8+
/// use re_rooting_dp::re_rooting_dp;
9+
///
10+
/// struct E(u64);
11+
/// #[derive(Clone)]
12+
/// struct V(u64);
13+
///
14+
/// let n: usize = todo!();
15+
/// let edges: Vec<(usize, usize, E)> = todo!();
16+
///
17+
/// let farthest = re_rooting_dp(
18+
/// n,
19+
/// &edges,
20+
/// // new
21+
/// |_i| {
22+
/// V(0)
23+
/// },
24+
/// // fold
25+
/// |p, ch, e| {
26+
/// V(p.0.max(ch.0 + e.0))
27+
/// }
28+
/// );
29+
/// ```
30+
pub fn re_rooting_dp<E, V, F, G>(n: usize, edges: &[(usize, usize, E)], new: F, fold: G) -> Vec<V>
31+
where
32+
V: Clone,
33+
F: Fn(usize) -> V,
34+
G: Fn(&V, &V, &E) -> V,
35+
{
36+
if n == 0 {
37+
return Vec::new();
38+
}
39+
40+
let (g, pre_order) = {
41+
let mut g = vec![vec![]; n];
42+
for (u, v, e) in edges {
43+
g[*u].push((*v, e));
44+
g[*v].push((*u, e));
45+
}
46+
let mut ord = Vec::with_capacity(n);
47+
let mut stack = vec![(0, usize::MAX)];
48+
while let Some((i, p)) = stack.pop() {
49+
ord.push(i);
50+
g[i].retain(|&(j, _)| j != p);
51+
for &(j, _) in &g[i] {
52+
stack.push((j, i));
53+
}
54+
}
55+
(g, ord)
56+
};
57+
58+
// 部分木に対するDP
59+
let dp_sub = {
60+
let mut dp_sub = (0..n).map(&new).collect::<Vec<_>>();
61+
for &i in pre_order.iter().rev() {
62+
for &(j, e) in &g[i] {
63+
dp_sub[i] = fold(&dp_sub[i], &dp_sub[j], e);
64+
}
65+
}
66+
dp_sub
67+
};
68+
69+
// 親方向に対するDP
70+
let mut dp_p = (0..n).map(&new).collect::<Vec<_>>();
71+
for i in pre_order {
72+
// 頂点iの子である全ての頂点jについてdp_p[j]を更新する
73+
apply(dp_p[i].clone(), &g[i], &fold, &dp_sub, &mut dp_p);
74+
}
75+
76+
dp_p.into_iter()
77+
.enumerate()
78+
.map(|(i, dp_p)| {
79+
g[i].iter()
80+
.fold(dp_p, |acc, &(j, e)| fold(&acc, &dp_sub[j], e))
81+
})
82+
.collect::<Vec<_>>()
83+
}
84+
85+
fn apply<E, V, G>(acc: V, children: &[(usize, &E)], fold: &G, dp_sub: &Vec<V>, dp_p: &mut Vec<V>)
86+
where
87+
V: Clone,
88+
G: Fn(&V, &V, &E) -> V,
89+
{
90+
if children.is_empty() {
91+
return;
92+
}
93+
94+
if children.len() == 1 {
95+
let (j, e) = children[0];
96+
dp_p[j] = fold(&dp_p[j], &acc, e);
97+
return;
98+
}
99+
100+
let (left, right) = children.split_at(children.len() / 2);
101+
let left_acc = left
102+
.iter()
103+
.fold(acc.clone(), |acc, &(j, e)| fold(&acc, &dp_sub[j], e));
104+
let right_acc = right
105+
.iter()
106+
.fold(acc, |acc, &(j, e)| fold(&acc, &dp_sub[j], e));
107+
apply(left_acc, right, fold, dp_sub, dp_p);
108+
apply(right_acc, left, fold, dp_sub, dp_p);
109+
}

0 commit comments

Comments
 (0)