2018 - Bike Paths
Explicación
Observemos que grupos de intersecciones pueden formar componentes fuertemente conexas. Por lo tanto, tratamos cada componente como un nodo con valor inicial igual al tamaño de la componente. Como las componentes fuertemente conexas resultantes forman un grafo dirigido acíclico (específicamente un árbol, por la “justicia” del enunciado), procesamos las aristas en orden topológico inverso con la siguiente relación, donde es el número de intersecciones que se pueden alcanzar desde la componente :
La respuesta final para la intersección es , ya que excluimos la intersección de partida de la respuesta.
Implementación
Complejidad temporal:
// CodeSnip{Benq Template}
/**
* Description: Kosaraju's Algorithm, DFS twice to generate
* strongly connected components in topological order. $a,b$
* in same component if both $a\to b$ and $b\to a$ exist.
* Time: O(N+M)
* Source: Wikipedia
* Verification: POI 8 peaceful commission
*/
struct SCC {
int N;
vector<vi> adj, radj;
vi todo, comp, comps;
vector<bool> vis;
void init(int _N) {
N = _N;
adj.rsz(N), radj.rsz(N), comp = vi(N, -1), vis.rsz(N);
}
void ae(int x, int y) { adj[x].pb(y), radj[y].pb(x); }
void dfs(int x) {
vis[x] = 1;
each(y, adj[x]) if (!vis[y]) dfs(y);
todo.pb(x);
}
void dfs2(int x, int v) {
comp[x] = v;
each(y, radj[x]) if (comp[y] == -1) dfs2(y, v);
}
void gen() { // fills allComp
F0R(i, N) if (!vis[i]) dfs(i);
reverse(all(todo));
each(x, todo) if (comp[x] == -1) dfs2(x, x), comps.pb(x);
}
};
int N, M;
int dp[100001];
int main() {
setIO();
re(N, M);
SCC scc;
scc.init(N);
F0R(i, M) {
int1(a, b);
scc.ae(a, b);
}
scc.gen();
F0R(i, N) { dp[scc.comp[i]]++; } // component size
reverse(all(scc.todo));
each(c, scc.todo) {
// use reverse edges since we process in reverse order
each(e, scc.radj[c]) {
if (scc.comp[c] != scc.comp[e]) { dp[scc.comp[e]] += dp[scc.comp[c]]; }
}
}
F0R(i, N) { ps(dp[scc.comp[i]] - 1); }
}