Pagini recente » Cod sursa (job #2765794) | Cod sursa (job #3311466) | Cod sursa (job #2512683) | Cod sursa (job #1275176) | Cod sursa (job #3306894)
#include <fstream>
#include <iostream>
#include <cassert>
#include <vector>
#include <algorithm>
template<class T> using vec = std::vector<T>;
constexpr int NIL = -1;
struct Arbore {
// arborele fara muchiile 'din stiva'
int root;
vec<int> par;
vec<vec<int>> kids;
vec<int> begin, end;
// vec<vec<int>> fwd;
// binary lifting cu toate muchiile
vec<int> sus, dep_sus, jump_sus;
Arbore( int n, const vec<vec<int>> &fwd ):
par(n), kids(n), begin(n), end(n),
sus(n), dep_sus(n), jump_sus(n)
{
vec<int> indeg(n, 0);
for( int u = 0; u < n; u++ )
for( int v : fwd[u] )
indeg[v]++;
vec<int> dep(n, 0);
auto dfs = [&]( auto &&self, int u ) -> void {
static int time = 0;
begin[u] = time++;
for( int v : fwd[u] ){
indeg[v]--;
if( indeg[v] > 0 ) continue;
par[v] = u;
dep[v] = 1 + dep[u];
kids[u].push_back( v );
self( self, v );
}
end[u] = time - 1;
};
root = std::find( indeg.begin(), indeg.end(), 0 ) - indeg.begin();
// std::cerr << "root = " << root << ", din " << n << "\n";
dep[root] = 0;
par[root] = root;
dfs( dfs, root );
for( int i = 0; i < n; i++ )
sus[i] = i;
for( int u = 0; u < n; u++ )
for( int v : fwd[u] )
sus[v] = (dep[u] < dep[sus[v]] ? u : sus[v]);
auto calc_lift = [&]( auto &&self, int u ) -> void {
for( int v : kids[u] ){
dep_sus[v] = 1 + dep_sus[sus[v]];
if( dep_sus[sus[v]] - dep_sus[jump_sus[sus[v]]] == dep_sus[jump_sus[sus[v]]] - dep_sus[jump_sus[jump_sus[sus[v]]]] )
jump_sus[v] = jump_sus[jump_sus[sus[v]]];
else
jump_sus[v] = sus[v];
self( self, v );
}
};
calc_lift( calc_lift, root );
}
bool reach( int src, int dest ) {
return begin[src] <= begin[dest] && begin[dest] <= end[src];
}
int dist( int src, int dest ) {
// urcam din src cat timp nu suntem intr-un nod care ajunge in dest
int ret = dep_sus[src];
while( !reach( src, dest ) ){
if( !reach( jump_sus[src], dest ) )
src = jump_sus[src];
else
src = sus[src];
}
ret -= dep_sus[src];
return ret;
}
};
int main() {
std::ifstream fin("obiective.in");
std::ofstream fout("obiective.out");
int n, m;
fin >> n >> m;
vec<int> node2comp(n);
vec<vec<int>> fwd; {
vec<vec<int>> _fwd(n), _back(n);
for( int i = 0; i < m; i++ ){
int a, b;
fin >> a >> b;
a--; b--;
_fwd[a].push_back( b );
_back[b].push_back( a );
}
vec<int> topo;
vec<bool> viz(n, false);
auto get_topo = [&]( auto &&self, int u ) -> void {
viz[u] = true;
for( int v : _fwd[u] )
if( !viz[v] )
self( self, v );
topo.push_back( u );
};
for( int i = 0; i < n; i++ )
if( !viz[i] )
get_topo( get_topo, i );
std::reverse( topo.begin(), topo.end() );
vec<int> ctc(n, NIL);
auto paint_ctc = [&]( auto &&self, int u ) -> void {
for( int v : _back[u] )
if( ctc[v] == NIL ){
ctc[v] = ctc[u];
self( self, v );
}
};
int nctc = 0;
for( int u : topo )
if( ctc[u] == NIL ){
ctc[u] = nctc++;
paint_ctc( paint_ctc, u );
}
node2comp = ctc;
// acum tot ce a ramas e sa facem muchiile din graful de ctc-uri..
// nu prea vad un motiv prea bun sa imi pese daca se repet muchii
// deci nu imi pasa
fwd.resize( nctc );
for( int u = 0; u < n; u++ )
for( int v : _fwd[u] )
if( ctc[u] != ctc[v] )
fwd[ctc[u]].push_back( ctc[v] );
}
Arbore zile((int)fwd.size(), fwd);
int q;
for( fin >> q; q--; ){
int a, b;
fin >> a >> b;
a = node2comp[a - 1];
b = node2comp[b - 1];
fout << zile.dist( a, b ) << '\n';
}
return 0;
}