Cod sursa(job #1534159)

Utilizator Andrei1998Andrei Constantinescu Andrei1998 Data 23 noiembrie 2015 14:04:19
Problema Obiective Scor 5
Compilator cpp Status done
Runda prep Marime 3.52 kb
#include <fstream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

const int NMAX = 32005;

vector <int> graph[NMAX];
vector <int> graph_inv[NMAX];

int _stack[NMAX];
int _stack_size;

bool vis[NMAX];
void dfs_inv (int node) {
    vis[node] = true;
    for (auto it: graph_inv[node])
        if (!vis[it])
            dfs_inv(it);
    _stack[++ _stack_size] = node;
}

int which_scc[NMAX];

void dfs (int node, int scc) {
    vis[node] = true;
    which_scc[node] = scc;

    for (auto it: graph[node])
        if (!vis[it])
            dfs(it, scc);
}

vector <int> new_graph[NMAX];
vector <int> tree_graph[NMAX];

int degs[NMAX];

int h[NMAX];
int fathers[15][NMAX];

void dfs_lca (int node) {
    h[node] = h[fathers[0][node]] + 1;
    for (int i = 1; i < 15; ++ i)
        fathers[i][node] = fathers[i - 1][fathers[i - 1][node]];

    for (auto it: tree_graph[node]) {
        fathers[0][it] = node;
        dfs_lca(it);
    }
}

int lca (int a, int b) {
    if (h[a] > h[b])
        swap(a, b);

    for (int i = 14; i >= 0; -- i)
        if (h[fathers[i][b]] >= h[a])
            b = fathers[i][b];

    if (a == b)
        return a;

    for (int i = 14; i >= 0; -- i)
        if (fathers[i][a] != fathers[i][b]) {
            a = fathers[i][a];
            b = fathers[i][b];
        }

    return fathers[0][a];
}

int sus[15][NMAX];

void dfs_sus0 (int node) {
    for (auto it: tree_graph[node]) {
        dfs_sus0(it);
        if (h[sus[0][it]] < h[sus[0][node]])
            sus[0][node] = sus[0][it];
    }
}

void dfs_sus (int node) {
    for (int i = 1; i < 15; ++ i)
        sus[i][node] = sus[i - 1][sus[i - 1][node]];

    for (auto it: tree_graph[node])
        dfs_sus(it);
}

int query (int a, int l) {
    int ans = 0;

    if (a == l)
        return 0;

    for (int i = 14; i >= 0; -- i)
        if (h[sus[i][a]] > h[l]) {
            a = sus[i][a];
            ++ ans;
        }

    return 1 + ans;
}

int main()
{
    ifstream cin("obiective.in");
    ofstream cout("obiective.out");

    int n = 0, m = 0;
    cin >> n >> m;

    int a, b;
    while (m --) {
        cin >> a >> b;

        graph[a].push_back(b);
        graph_inv[b].push_back(a);
    }

    for (int i = 1; i <= n; ++ i)
        if (!vis[i])
            dfs_inv(i);

    memset(vis, 0, sizeof(vis));

    int sccs = 0;
    for (int i = n; i; -- i)
        if (!vis[_stack[i]])
            dfs(_stack[i], ++ sccs);

    for (int i = 1; i <= n; ++ i)
        for (auto it: graph[i])
            if (which_scc[i] != which_scc[it])
                new_graph[which_scc[i]].push_back(which_scc[it]);
    n = sccs;

    //Deschiderea tranzitiva
    for (int i = 1; i <= n; ++ i)
        for (auto it: new_graph[i]) {
            if (!degs[it]) {
                ++ degs[it];
                tree_graph[i].push_back(it);
            }
        }

    dfs_lca(n);

    //Calculam sus-urilie
    for (int i = 1; i <= n; ++ i)
        sus[0][i] = i;

    for (int i = 1; i <= n; ++ i)
        for (auto it: new_graph[i])
            if (h[i] < h[sus[0][it]])
                sus[0][it] = i;

    dfs_sus0(n);
    dfs_sus(n);

    //Raspundem la query-uri
    int q = 0;
    cin >> q;

    int l;
    while (q --) {
        cin >> a >> b;
        a = which_scc[a], b = which_scc[b];

        l = lca(a, b);
        cout << query(a, l) << '\n';
    }

    cin.close();
    cout.close();
    return 0;
}