Cod sursa(job #2664726)

Utilizator DawlauAndrei Blahovici Dawlau Data 29 octombrie 2020 11:04:54
Problema Obiective Scor 5
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.89 kb
#include <bits/stdc++.h>

using namespace std;

ifstream fin("obiective.in");
ofstream fout("obiective.out");


vector < vector <int> > g, tg, SCCs, sparseTable, anc;
vector < set <int> > mg; // meta graph
vector <int> topoSort, SCC, depth, fp;
vector <bool> seen;
int V, E;
int numSCC;
int eulerOrd;


void readGraph(){

    fin >> V >> E;

    g.resize(V + 1);
    tg.resize(V + 1);
    topoSort.reserve(V);
    SCCs.reserve(V);
    SCC.resize(V + 1);
    seen.resize(V + 1);


    for(int e = 0; e < E; ++e){

        int from, to;
        fin >> from >> to;

        g[from].push_back(to);
        tg[to].push_back(from);
    }
}


void topologicalSort(int node){

    seen[node] = true;

    for(const int &adj : g[node])
        if(!seen[adj])
            topologicalSort(adj);

    topoSort.push_back(node);
}


void DFS(int node, vector <int> &component){

    seen[node] = false;
    SCC[node] = numSCC;
    component.push_back(node);

    for(const int &adj : tg[node])
        if(seen[adj])
            DFS(adj, component);
}


void build_mg(){

    mg.resize(numSCC + 1);

    for(int scc = 0; scc < numSCC; ++scc)
        for(int &node : SCCs[scc])
            for(int &adj : g[node])
                if(SCC[node] != SCC[adj])
                    mg[scc + 1].insert(SCC[adj] + 1);

    V = numSCC;

    depth.resize(V + 1);
    sparseTable.resize((int)log2(2 * V + 2) + 1, vector <int>(2 * V + 2) );
    fp.resize(V + 1);
    anc.resize((int)log2(V + 1) + 1, vector <int>(V + 1));

    depth[0] = INT_MAX;
}


int minDepth(int a, int b){

    if(depth[a] < depth[b])
        return a;
    return b;
}


void eulerTrav(int node, int d){

    seen[node] = true;
    depth[node] = d;
    sparseTable[0][++eulerOrd] = node;
    fp[node] = eulerOrd;

    for(const int &adj : mg[node])
        if(!seen[adj]){ // tree edge

            anc[0][adj] = minDepth(anc[0][adj], node);
            eulerTrav(adj, d + 1);
            sparseTable[0][++eulerOrd] = node;
            anc[0][node] = minDepth(anc[0][node], anc[0][adj]);
        }
        else { // fwd edge
            anc[0][adj] = min(anc[0][adj], node);
        }
}


void createSparseTable(){

    for(int r = 1; (1 << r) <= eulerOrd; ++r)
        for(int c = 1; c <= eulerOrd - (1 << r) + 1; ++c)
            sparseTable[r][c] = minDepth(sparseTable[r - 1][c], sparseTable[r - 1][c + (1 << (r - 1))]);
}


void createAnc(){

    for(int step = 1; (1 << step) <= V; ++step)
        for(int node = 1; node <= V; ++node)
            anc[step][node] = anc[step - 1][anc[step - 1][node]];
}


int LCA(int x, int y){

    if(fp[x] > fp[y])
        swap(x, y);

    int seqLen = fp[y] - fp[x] + 1;
    int lvl = (int)(log2(seqLen));

    return minDepth(sparseTable[lvl][fp[x]], sparseTable[lvl][fp[x] + seqLen - (1 << lvl)]);
}


int main(){

    readGraph();

    for(int node = 1; node <= V; ++node)
        if(!seen[node])
            topologicalSort(node);

    for(int idx = V - 1; idx >= 0; --idx)
        if(seen[topoSort[idx]]){

            vector <int> component;
            component.reserve(V);

            DFS(topoSort[idx], component);
            SCCs.push_back(component);

            ++numSCC;
        }

    build_mg();

    eulerTrav(1, 1);
    createSparseTable();
    createAnc();

    for(int r = 0;r < (int)anc.size(); ++r){

        for(int c = 0; c < (int)anc[r].size(); ++c)
            cout << anc[r][c] << ' ';
        cout << '\n';
    }

    int maxStep = (int)log2(V);

    int T;
    fin >> T;

    for(; T; --T){

        int a, b;
        fin >> a >> b;

        a = SCC[a] + 1;
        b = SCC[b] + 1;

        int lca = LCA(a, b);

        if(a == lca)
            fout << 0 << '\n';
        else{

            int ans = 0;
            for(int step = maxStep; step >= 0; --step)
                if(depth[anc[step][a]] > depth[lca]){

                    ans += (1 << step);
                    a = anc[step][a];
                }

            fout << ans + 1 << '\n';
        }
    }
}