Cod sursa(job #3255713)

Utilizator AlexandruBenescuAlexandru Benescu AlexandruBenescu Data 11 noiembrie 2024 23:57:18
Problema Obiective Scor 35
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.31 kb
#include <bits/stdc++.h>
#define L 32005
#define S 16
using namespace std;
ifstream fin("obiective.in");
ofstream fout("obiective.out");

int n, m, q;
vector <int> G[L], G_reversed[L], topologicalSorting, ctc[L];
vector <pair <int, int>> edges, specialEdges;
int ctcIndex, nodeCtc[L];
bool vis[L];
map <pair <int, int>, bool> mp;
int inDeg[L], root;
queue <int> Q;
int t[S][L], lev[L], h[L], th[S][L];

void dfs(int node) {
  vis[node] = true;
  for (auto it : G[node])
    if (!vis[it])
      dfs(it);
  topologicalSorting.push_back(node);
}

void clearVis() {
  for (int i = 1; i <= n; i++)
    vis[i] = false;
}

void createStrongComponent(int node) {
  ctc[ctcIndex].push_back(node);
  vis[node] = true;
  for (auto it : G_reversed[node])
    if (!vis[it])
      createStrongComponent(it);
}

void getCTC() {
  for (int i = 1; i <= n; i++) {
    if (vis[i])
      continue;
    dfs(i);
  }
  clearVis();
  reverse(topologicalSorting.begin(), topologicalSorting.end());
  for (auto it : topologicalSorting) {
    if (vis[it])
      continue;
    createStrongComponent(it);
    ctcIndex++;
  }

  for (int i = 0; i < ctcIndex; i++)
    for (auto it : ctc[i])
      nodeCtc[it] = i + 1;
}

void generateDAG() {
  for (int i = 1; i <= n; i++)
    G[i].clear();
  n = ctcIndex;
  for (auto edge : edges) {
    if (nodeCtc[edge.first] != nodeCtc[edge.second] && !mp[{nodeCtc[edge.first], nodeCtc[edge.second]}]) {
      mp[{nodeCtc[edge.first], nodeCtc[edge.second]}] = true;
      G[nodeCtc[edge.first]].push_back(nodeCtc[edge.second]);
      inDeg[nodeCtc[edge.second]]++;
    }
  }

  for (int i = 1; i <= n; i++) {
    if (inDeg[i] == 0)
      root = i;
  }
}

void getSpecialEdges() {
  mp.clear();
  Q.push(root);
  while (!Q.empty()) {
    int node = Q.front();
    Q.pop();
    for (auto it : G[node]) {
      inDeg[it]--;
      if (inDeg[it] == 0) {
        mp[{node, it}] = true;
        Q.push(it);
      }
    }
  }
  for (int i = 1; i <= n; i++)
    for (auto it : G[i])
      if (!mp[{i, it}])
        specialEdges.push_back({i, it});

  for (int i = 1; i <= n; i++)
    for (int j = 0; j < (int)G[i].size(); j++)
      if (!mp[{i, G[i][j]}])
        G[i][j] = i;
}

void dfsT(int node) {
  vis[node] = true;
  for (auto it : G[node]) {
    if (vis[it] == true)
      continue;
    t[0][it] = node;
    lev[it] = lev[node] + 1;
    dfsT(it);
  }
}

void buildLCA() {
  t[0][root] = root;
  lev[root] = 1;
  clearVis();
  dfsT(root);
  for (int bit = 1; bit < S; bit++)
    for (int i = 1; i <= n; i++)
      t[bit][i] = t[bit - 1][t[bit - 1][i]];
}

int getKthParent(int node, int k) {
  for (int bit = 0; bit < S; bit++)
    if (k & (1 << bit))
      node = t[bit][node];
  return node;
}

int lca(int x, int y) {
  if (lev[x] < lev[y])
    swap(x, y);
  x = getKthParent(x, lev[x] - lev[y]);
  if (x == y)
    return x;
  for (int bit = S - 1; bit >= 0; bit--)
    if (t[bit][x] != t[bit][y]) {
      x = t[bit][x];
      y = t[bit][y];
    }
  return t[0][x];
}

void dfsH(int node) {
  vis[node] = true;
  for (auto it : G[node]) {
    if (!vis[it]) {
      dfsH(it);
      if (lev[h[node]] > lev[h[it]]) {
        h[node] = h[it];
      }
    }
  }
}

void buildH() {
  for (int i = 1; i <= n; i++)
    h[i] = t[0][i];
  for (auto it : specialEdges)
    h[it.second] = it.first;
  clearVis();
  dfsH(root);
}

void buildTh() {
  for (int i = 1; i <= n; i++)
    th[0][i] = h[i];
  for (int bit = 1; bit < S; bit++)
    for (int i = 1; i <= n; i++)
      th[bit][i] = th[bit - 1][th[bit - 1][i]];
}

int countOp(int x, int y) {
  if (lev[x] <= lev[y])
    return 0;
  int op = 0;
  for (int bit = S - 1; bit >= 0; bit--) {
    if (lev[th[bit][x]] > lev[y]) {
      op += (1 << bit);
      x = th[bit][x];
    }
  }
  return op + 1;
}

int main() {
  fin >> n >> m;
  for (int i = 1; i <= m; i++) {
    int a, b;
    fin >> a >> b;
    G[a].push_back(b);
    G_reversed[b].push_back(a);
    edges.push_back({a, b});
  }

  getCTC();
  generateDAG();
  getSpecialEdges();
  buildLCA();
  buildH();
  buildTh();

  fin >> q;
  for (int i = 1; i <= q; i++) {
    int a, b;
    fin >> a >> b;
    a = nodeCtc[a];
    b = nodeCtc[b];
    fout << countOp(a, lca(a, b)) << "\n";
  }
  return 0;
}