forked from NASU41/AtCoderLibraryForJava
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSCC.java
More file actions
127 lines (120 loc) · 3.97 KB
/
SCC.java
File metadata and controls
127 lines (120 loc) · 3.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
class SCC {
static class Edge {
int from, to;
public Edge(int from, int to) {
this.from = from; this.to = to;
}
}
final int n;
int m;
final java.util.ArrayList<Edge> unorderedEdges;
final int[] start;
final int[] ids;
boolean hasBuilt = false;
public SCC(int n) {
this.n = n;
this.unorderedEdges = new java.util.ArrayList<>();
this.start = new int[n + 1];
this.ids = new int[n];
}
public void addEdge(int from, int to) {
unorderedEdges.add(new Edge(from, to));
start[from + 1]++;
this.m++;
}
public int id(int i) {
if (!hasBuilt) {
throw new UnsupportedOperationException(
"Graph hasn't been built."
);
}
return ids[i];
}
public int[][] build() {
for (int i = 1; i <= n; i++) {
start[i] += start[i - 1];
}
Edge[] orderedEdges = new Edge[m];
int[] count = new int[n + 1];
System.arraycopy(start, 0, count, 0, n + 1);
for (Edge e : unorderedEdges) {
orderedEdges[count[e.from]++] = e;
}
int nowOrd = 0;
int groupNum = 0;
int k = 0;
// parent
int[] par = new int[n];
int[] vis = new int[n];
int[] low = new int[n];
int[] ord = new int[n];
java.util.Arrays.fill(ord, -1);
// u = lower32(stack[i]) : visiting vertex
// j = upper32(stack[i]) : jth child
long[] stack = new long[n];
// size of stack
int ptr = 0;
// non-recursional DFS
for (int i = 0; i < n; i++) {
if (ord[i] >= 0) continue;
par[i] = -1;
// vertex i, 0th child.
stack[ptr++] = 0l << 32 | i;
// stack is not empty
while (ptr > 0) {
// last element
long p = stack[--ptr];
// vertex
int u = (int) (p & 0xffff_ffffl);
// jth child
int j = (int) (p >>> 32);
if (j == 0) { // first visit
low[u] = ord[u] = nowOrd++;
vis[k++] = u;
}
if (start[u] + j < count[u]) { // there are more children
// jth child
int to = orderedEdges[start[u] + j].to;
// incr children counter
stack[ptr++] += 1l << 32;
if (ord[to] == -1) { // new vertex
stack[ptr++] = 0l << 32 | to;
par[to] = u;
} else { // backward edge
low[u] = Math.min(low[u], ord[to]);
}
} else { // no more children (leaving)
while (j --> 0) {
int to = orderedEdges[start[u] + j].to;
// update lowlink
if (par[to] == u) low[u] = Math.min(low[u], low[to]);
}
if (low[u] == ord[u]) { // root of a component
while (true) { // gathering verticies
int v = vis[--k];
ord[v] = n;
ids[v] = groupNum;
if (v == u) break;
}
groupNum++; // incr the number of components
}
}
}
}
for (int i = 0; i < n; i++) {
ids[i] = groupNum - 1 - ids[i];
}
int[] counts = new int[groupNum];
for (int x : ids) counts[x]++;
int[][] groups = new int[groupNum][];
for (int i = 0; i < groupNum; i++) {
groups[i] = new int[counts[i]];
}
for (int i = 0; i < n; i++) {
int cmp = ids[i];
groups[cmp][--counts[cmp]] = i;
}
hasBuilt = true;
return groups;
}
}