Cod sursa(job #3306896)

Utilizator mircea_007Mircea Rebengiuc mircea_007 Data 14 august 2025 23:16:54
Problema Obiective Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.37 kb
#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<vec<int>> kids;
  vec<int> begin, end;
  // vec<vec<int>> fwd;

  // binary lifting cu toate muchiile
  vec<int> sus, dep_sus, jump_sus;

  bool reach( int src, int dest ) {
    return begin[src] <= begin[dest] && begin[dest] <= end[src];
  }

  Arbore( int n, const vec<vec<int>> &fwd ):
    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);
    vec<bool> viz(n, false);
    auto dfs = [&]( auto &&self, int u ) -> void {
      static int time = 0;
      viz[u] = true;
      begin[u] = time++;

      for( int v : fwd[u] )
        indeg[v]--;

      for( int v : fwd[u] ){
        if( indeg[v] > 0 ) continue;
        if( viz[v] ) continue;

        dep[v] = 1 + dep[u];
        kids[u].push_back( v );
        self( self, v );
      }

      end[u] = time - 1;

      // std::cerr << u << "(" << begin[u] << ", " << end[u] << ")\n";
    };

    for( int u = 0; u < n; u++ )
      for( int v : fwd[u] )
        assert( reach( u, v ) );

    root = std::find( indeg.begin(), indeg.end(), 0 ) - indeg.begin();

    dep[root] = 0;
    dfs( dfs, root );

    { // calculeaza sus[]
      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 prop_sus = [&]( auto &&self, int u ) -> void {
        for( int v : kids[u] ){
          self( self, v );
          sus[u] = (dep[sus[u]] < dep[sus[v]] ? sus[u] : sus[v]);
        }
      };

      prop_sus( prop_sus, root );
    }

    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 );
  }

  int dist( int src, int dest ) {
    // std::cerr << "src = " << src << ", dep_sus[src] = " << dep_sus[src] << ", dest = " << dest << ", dep_sus[dest] = " << dep_sus[dest] << "\n";
    // 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;
}