Skip to content

Commit 97823b6

Browse files
authored
Merge pull request #312 from xirc/euler-tour
Redesign tree/euler-tour
2 parents c1ed8d7 + 1f6c80a commit 97823b6

File tree

8 files changed

+205
-127
lines changed

8 files changed

+205
-127
lines changed

aoj/GRL/GRL5D/main.cpp

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,49 @@
1-
#include <vector>
2-
#include <stack>
1+
//https://onlinejudge.u-aizu.ac.jp/problems/GRL_5_D
32

4-
class EulerTrour {
5-
int N;
6-
std::vector<std::vector<int>> adj;
3+
#include <bits/stdc++.h>
4+
5+
class EulerTour {
6+
private:
7+
size_t N;
8+
std::vector<std::vector<size_t>> adj;
79

810
public:
9-
// O(V)
10-
EulerTrour(int size): N(size), adj(size) {}
11-
// O(1)
12-
int size() {
11+
// Time: O(V)
12+
EulerTour(size_t const N = 0): N(N), adj(N) {}
13+
// Time: O(1)
14+
size_t size() const {
1315
return N;
1416
}
15-
// O(1)
16-
void add_edge(int u, int v) {
17-
throw_if_invalid_index(u);
18-
throw_if_invalid_index(v);
17+
// u = [0,N), v = [0,N)
18+
// Time: O(1)
19+
void add_edge(size_t const u, size_t const v) {
20+
if (u >= N) throw std::out_of_range("u");
21+
if (v >= N) throw std::out_of_range("v");
1922
adj[u].push_back(v);
2023
adj[v].push_back(u);
2124
}
22-
// O(E)
23-
void solve(int r, std::vector<int>& tour, std::vector<int>& tin, std::vector<int>& tout) {
24-
throw_if_invalid_index(r);
25+
// r = [0,N)
26+
// Time: O(E)
27+
void solve(size_t r, std::vector<size_t>& tour, std::vector<size_t>& tin, std::vector<size_t>& tout) const {
28+
if (r >= N) throw std::out_of_range("r");
2529

26-
std::stack<std::pair<int,int>> S;
30+
std::stack<std::pair<size_t,int>> S;
2731
std::vector<bool> visited(N, false);
2832

2933
tour.clear();
30-
tin.assign(N, -1);
31-
tout.assign(N, -1);
34+
tin.assign(N, 2 * N);
35+
tout.assign(N, 2 * N);
3236

3337
S.push({r,-1});
3438
while (S.size()) {
35-
int v = S.top().first;
39+
size_t v = S.top().first;
3640
int& i = S.top().second;
3741
if (i < 0) {
3842
visited[v] = true;
3943
tour.push_back(v);
4044
tin[v] = tour.size() - 1;
41-
} else if (i < adj[v].size()) {
42-
int u = adj[v][i];
45+
} else if (size_t(i) < adj[v].size()) {
46+
auto u = adj[v][i];
4347
if (!visited[u]) S.push({u,-1});
4448
} else {
4549
tour.push_back(v);
@@ -49,20 +53,8 @@ class EulerTrour {
4953
i++;
5054
}
5155
}
52-
53-
private:
54-
void throw_if_invalid_index(int index) {
55-
if (index < 0 || index >= N) throw "index out of range";
56-
}
5756
};
5857

59-
#include <vector>
60-
#include <functional>
61-
62-
// BinaryIndexedTree
63-
// Memory O(N)
64-
// Query O(logN)
65-
// Update O(logN)
6658
template <class T = long long>
6759
class BinaryIndexedTree {
6860
public:
@@ -132,8 +124,6 @@ class BinaryIndexedTree {
132124
};
133125

134126

135-
#include <iostream>
136-
137127
using namespace std;
138128

139129
int main() {
@@ -143,7 +133,7 @@ int main() {
143133
int N, Q;
144134

145135
cin >> N;
146-
EulerTrour euler_tour(N);
136+
EulerTour euler_tour(N);
147137
for (int i = 0; i < N; ++i) {
148138
int K, c;
149139
cin >> K;
@@ -153,7 +143,7 @@ int main() {
153143
}
154144
}
155145

156-
vector<int> tour, tin, tout;
146+
vector<size_t> tour, tin, tout;
157147
euler_tour.solve(0, tour, tin, tout);
158148
BinaryIndexedTree<long long> bit(2*N);
159149

aoj/GRL/GRL5D/sample1.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
6
2+
2 1 2
3+
2 3 5
4+
0
5+
0
6+
0
7+
1 4
8+
7
9+
1 1
10+
0 3 10
11+
1 2
12+
0 4 20
13+
1 3
14+
0 5 40
15+
1 4

aoj/GRL/GRL5D/sample2.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
4
2+
1 1
3+
1 2
4+
1 3
5+
0
6+
6
7+
0 3 1000
8+
0 2 1000
9+
0 1 1000
10+
1 1
11+
1 2
12+
1 3

aoj/GRL/GRL5D/sample3.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2
2+
1 1
3+
0
4+
4
5+
0 1 1
6+
1 1
7+
0 1 1
8+
1 1

lib/cpalgo/tree/euler-tour.hpp

Lines changed: 0 additions & 65 deletions
This file was deleted.

lib/cpalgo/tree/euler_tour.hpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#pragma once
2+
3+
#include <stack>
4+
#include <stdexcept>
5+
#include <vector>
6+
7+
8+
// Euler Tour in Tree
9+
//
10+
// Space: O(V + E)
11+
//
12+
// NOTE:
13+
// - undirected
14+
// - non-loop
15+
// - non-multi-edge
16+
// - it can handle a forest
17+
//
18+
// Verified:
19+
// - https://onlinejudge.u-aizu.ac.jp/problems/GRL_5_D
20+
//
21+
class EulerTour {
22+
private:
23+
size_t N;
24+
std::vector<std::vector<size_t>> adj;
25+
26+
public:
27+
// Time: O(V)
28+
EulerTour(size_t const N = 0): N(N), adj(N) {}
29+
// Time: O(1)
30+
size_t size() const {
31+
return N;
32+
}
33+
// u = [0,N), v = [0,N)
34+
// Time: O(1)
35+
void add_edge(size_t const u, size_t const v) {
36+
if (u >= N) throw std::out_of_range("u");
37+
if (v >= N) throw std::out_of_range("v");
38+
adj[u].push_back(v);
39+
adj[v].push_back(u);
40+
}
41+
// r = [0,N)
42+
// Time: O(E)
43+
void solve(size_t r, std::vector<size_t>& tour, std::vector<size_t>& tin, std::vector<size_t>& tout) const {
44+
if (r >= N) throw std::out_of_range("r");
45+
46+
std::stack<std::pair<size_t,int>> S;
47+
std::vector<bool> visited(N, false);
48+
49+
tour.clear();
50+
tin.assign(N, 2 * N);
51+
tout.assign(N, 2 * N);
52+
53+
S.push({r,-1});
54+
while (S.size()) {
55+
size_t v = S.top().first;
56+
int& i = S.top().second;
57+
if (i < 0) {
58+
visited[v] = true;
59+
tour.push_back(v);
60+
tin[v] = tour.size() - 1;
61+
} else if (size_t(i) < adj[v].size()) {
62+
auto u = adj[v][i];
63+
if (!visited[u]) S.push({u,-1});
64+
} else {
65+
tour.push_back(v);
66+
tout[v] = tour.size() - 1;
67+
S.pop();
68+
}
69+
i++;
70+
}
71+
}
72+
};
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include <bits/stdc++.h>
2+
#include "gtest/gtest.h"
3+
#include "cpalgo/tree/euler_tour.hpp"
4+
5+
using namespace std;
6+
7+
8+
TEST(EulerTourTest, IsEmptyInitially) {
9+
EulerTour solver;
10+
EXPECT_EQ(0ULL, solver.size());
11+
}
12+
13+
TEST(EulerTourTest, ShouldComputeEulerTour) {
14+
EulerTour solver(7);
15+
EXPECT_EQ(7ULL, solver.size());
16+
17+
solver.add_edge(0, 1);
18+
solver.add_edge(1, 2);
19+
solver.add_edge(1, 3);
20+
solver.add_edge(0, 4);
21+
solver.add_edge(0, 5);
22+
solver.add_edge(5, 6);
23+
24+
vector<size_t> tour, tin, tout;
25+
solver.solve(0, tour, tin, tout);
26+
27+
vector<size_t> expected_tour = { 0, 1, 2, 2, 3, 3, 1, 4, 4, 5, 6, 6, 5, 0 };
28+
vector<size_t> expected_tin = { 0, 1, 2, 4, 7, 9, 10 };
29+
vector<size_t> expected_tout = { 13, 6, 3, 5, 8, 12, 11 };
30+
EXPECT_EQ(expected_tour, tour);
31+
EXPECT_EQ(expected_tin, tin);
32+
EXPECT_EQ(expected_tout, tout);
33+
}
34+
35+
TEST(EulerTourTest, ShouldHandleAForest) {
36+
EulerTour solver(7);
37+
EXPECT_EQ(7ULL, solver.size());
38+
39+
solver.add_edge(0, 1);
40+
solver.add_edge(1, 2);
41+
solver.add_edge(1, 3);
42+
solver.add_edge(5, 6);
43+
44+
vector<size_t> tour, tin, tout;
45+
solver.solve(0, tour, tin, tout);
46+
47+
vector<size_t> expected_tour = { 0, 1, 2, 2, 3, 3, 1, 0 };
48+
vector<size_t> expected_tin = { 0, 1, 2, 4, 14, 14, 14 };
49+
vector<size_t> expected_tout = { 7, 6, 3, 5, 14, 14, 14 };
50+
EXPECT_EQ(expected_tour, tour);
51+
EXPECT_EQ(expected_tin, tin);
52+
EXPECT_EQ(expected_tout, tout);
53+
}

0 commit comments

Comments
 (0)