Skip to content

Commit 724b253

Browse files
committed
Separate spfa and deep_spfa, add spfa tree diameter test
1 parent 6c332cb commit 724b253

File tree

2 files changed

+88
-20
lines changed

2 files changed

+88
-20
lines changed

cp-algo/graph/shortest_path.hpp

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace cp_algo::graph {
1616
: dist(n, inf), pre(n) {}
1717
};
1818

19-
struct dijkstra_context : shortest_path_context {
19+
struct dijkstra_context: shortest_path_context {
2020
struct que_t {
2121
int64_t dist;
2222
node_index v;
@@ -44,23 +44,44 @@ namespace cp_algo::graph {
4444
}
4545
};
4646

47-
struct spfa_context : shortest_path_context {
47+
struct spfa_context: shortest_path_context {
4848
std::queue<node_index> que;
4949
std::vector<char> flags;
5050
static constexpr char in_queue = 1;
5151
static constexpr char invalidated = 2;
52+
53+
spfa_context(int n) : shortest_path_context(n), flags(n) {}
54+
55+
void push(node_index, node_index v) {
56+
if (!(flags[v] & in_queue)) {
57+
que.push(v);
58+
flags[v] |= in_queue;
59+
}
60+
}
61+
62+
std::optional<node_index> next_node() {
63+
while (!que.empty()) {
64+
node_index v = que.front();
65+
que.pop();
66+
flags[v] &= ~in_queue;
67+
if (!(flags[v] & invalidated)) {
68+
return v;
69+
}
70+
}
71+
return std::nullopt;
72+
}
73+
};
74+
75+
struct deep_spfa_context: spfa_context {
5276
std::vector<std::basic_string<node_index>> dependents;
5377

54-
spfa_context(int n) : shortest_path_context(n), flags(n), dependents(n) {}
78+
deep_spfa_context(int n) : spfa_context(n), dependents(n) {}
5579

5680
void push(node_index u, node_index v) {
5781
invalidate_subtree(v);
5882
dependents[u].push_back(v);
5983
flags[v] &= ~invalidated;
60-
if (!(flags[v] & in_queue)) {
61-
que.push(v);
62-
flags[v] |= in_queue;
63-
}
84+
spfa_context::push(u, v);
6485
}
6586

6687
void invalidate_subtree(node_index v) {
@@ -69,6 +90,7 @@ namespace cp_algo::graph {
6990
node_index u = to_invalidate.back();
7091
to_invalidate.pop_back();
7192
flags[u] |= invalidated;
93+
flags[u] &= ~in_queue;
7294
for (auto dep: dependents[u]) {
7395
if (pre[dep].u == u) {
7496
to_invalidate.push_back(dep);
@@ -77,18 +99,6 @@ namespace cp_algo::graph {
7799
dependents[u].clear();
78100
}
79101
}
80-
81-
std::optional<node_index> next_node() {
82-
while (!que.empty()) {
83-
node_index v = que.front();
84-
que.pop();
85-
flags[v] &= ~in_queue;
86-
if (!(flags[v] & invalidated)) {
87-
return v;
88-
}
89-
}
90-
return std::nullopt;
91-
}
92102
};
93103

94104
template<typename Context, weighted_graph_type graph>
@@ -119,14 +129,18 @@ namespace cp_algo::graph {
119129
shortest_path_context spfa(graph const& g, node_index s) {
120130
return sssp_impl<spfa_context>(g, s);
121131
}
132+
template<weighted_graph_type graph>
133+
shortest_path_context deep_spfa(graph const& g, node_index s) {
134+
return sssp_impl<deep_spfa_context>(g, s);
135+
}
122136

123137
template<weighted_graph_type graph>
124138
shortest_path_context single_source_shortest_path(graph const& g, node_index s) {
125139
bool negative_edges = false;
126140
for (auto e: g.edges()) {
127141
negative_edges |= e.w < 0;
128142
}
129-
return negative_edges ? spfa(g, s) : dijkstra(g, s);
143+
return negative_edges ? deep_spfa(g, s) : dijkstra(g, s);
130144
}
131145

132146
std::vector<edge_index> recover_path(auto const& pre, node_index s, node_index t) {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// @brief Tree Diameter
2+
#define PROBLEM "https://judge.yosupo.jp/problem/tree_diameter"
3+
#pragma GCC optimize("Ofast,unroll-loops")
4+
#include <iostream>
5+
#include "blazingio/blazingio.min.hpp"
6+
#include "cp-algo/graph/shortest_path.hpp"
7+
#include <bits/stdc++.h>
8+
9+
using namespace std;
10+
using namespace cp_algo::graph;
11+
12+
template<weighted_undirected_graph_type graph>
13+
std::tuple<int64_t, node_index, std::vector<edge_index>> tree_diameter(graph const& g) {
14+
auto [d1, _] = spfa(g, 0);
15+
node_index s = 0;
16+
for(auto v: g.nodes()) {
17+
if (d1[v] > d1[s]) {
18+
s = v;
19+
}
20+
}
21+
auto [d2, pre] = spfa(g, s);
22+
node_index t = 0;
23+
for(auto v: g.nodes()) {
24+
if (d2[v] > d2[t]) {
25+
t = v;
26+
}
27+
}
28+
return {d2[t], s, recover_path(pre, s, t)};
29+
}
30+
31+
void solve() {
32+
int n;
33+
cin >> n;
34+
weighted_graph g(n);
35+
g.read_edges(n - 1);
36+
auto [d, s, path] = tree_diameter(g);
37+
cout << d << ' ' << size(path) + 1 << '\n';
38+
cout << s;
39+
for(auto e: path) {
40+
cout << ' ' << g.edge(e).to;
41+
}
42+
cout << "\n";
43+
}
44+
45+
signed main() {
46+
//freopen("input.txt", "r", stdin);
47+
ios::sync_with_stdio(0);
48+
cin.tie(0);
49+
int t = 1;
50+
//cin >> t;
51+
while(t--) {
52+
solve();
53+
}
54+
}

0 commit comments

Comments
 (0)