Cod sursa(job #3307284)

Utilizator Nasa1004Ema Nicole Gheorghe Nasa1004 Data 19 august 2025 16:13:37
Problema Obiective Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.61 kb
#include <fstream>
#include <bitset>
#include <vector>
#include <set>

using namespace std;
const int NMAX = 32000;
const int LOG = 16;

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

bitset <NMAX + 2> f;
void dfsctc(int start, vector <vector <int>>& adj, vector <int>& add_to) {
    f[start] = 1;
    for(auto nod : adj[start]) {
        if(!f[nod])
            dfsctc(nod, adj, add_to);
    }
    add_to.push_back(start);
}
vector <vector <int>> adj, inv;
vector <int> topo, aux;
int ctc[NMAX + 2]; ///fiec nod din ce comp de ctc apartine

set <pair <int, int>> edges; //noile muchii
vector <vector <int>> v; ///muchiile dintre ctc-uri

int tata[NMAX + 2], niv[NMAX + 2];
int up[NMAX + 2][LOG + 1];
void dfstree(int start) {
    f[start] = 1;
    for(auto nod : v[start]) {
        if(!f[nod]) {
            tata[nod] = start;
            niv[nod] = niv[start] + 1;

            ///built binary lifting pt lca
            up[nod][0] = start;
            for(int j = 1; j < LOG; j++)
                up[nod][j] = up[up[nod][j - 1]][j - 1];

            dfstree(nod);
        }
        else
            inv[nod].push_back(start);
    }
}

int sub[NMAX + 2]; ///sub[nod] - pt subarborele lui nod, nodul cu niv maxim la care se poate ajunge
///dc luam o singura muchie de intoarcere (sau normala)
int dp[NMAX + 2][LOG + 1]; ///dp[i][j] - pt nodul i, nodul cel mai de sus la care poti ajunge,
                          ///dc sari peste 2^j muchii in sus\

void dfsaux(int start) { ///STRICT pt aux
    f[start] = 1;
    sub[start] = tata[start]; ///init
    if(start == 1)
        sub[start] = 1;
    for(auto x : inv[start]) { ///toate muchiile de intoarcere care ajung in start
        if(niv[x] < niv[sub[start]])
            sub[start] = x;
    }
    for(auto nod : v[start]) {
        if(!f[nod]) {
            dfsaux(nod);
            if(niv[sub[nod]] < niv[sub[start]])
                sub[start] = sub[nod];
        }
    }
}
void dfsdp(int start) {
    f[start] = 1;
    dp[start][0] = sub[start]; ///calc dp-ul
    for(int j = 1; j < LOG; j++)
        dp[start][j] = dp[dp[start][j - 1]][j - 1];
    for(auto nod : v[start]) {
        if(!f[nod])
            dfsdp(nod);
    }
}

int LCA(int a, int b) {
    if(niv[a] < niv[b])
        swap(a, b);
    int k = niv[a] - niv[b];
    for(int j = LOG - 1; j >= 0; j--) {
        if(k & (1 << j))
            a = up[a][j];
    }
    if(a == b)
        return a;
    for(int j = LOG - 1; j >= 0; j--) {
        if(up[a][j] != up[b][j]) {
            a = up[a][j];
            b = up[b][j];
        }
    }
    return up[a][0];
}

int query(int a, int b) {
    if(a == b)
        return 0;
    int ans = 1;
    for(int j = LOG - 1; j >= 0; j--) {
        if(niv[dp[a][j]] > niv[b]) {
            ans += (1 << j);
            a = dp[a][j];
        }
    }
    return ans;
}

int main() {
    int n, m;
    cin >> n >> m;

    ///FORMAM CTC-URILE
    adj.resize(n + 1);
    inv.resize(n + 1);
    for(int i = 1; i <= m; i++) {
        int a, b;
        cin >> a >> b;
        adj[a].push_back(b);
        inv[b].push_back(a);
    }
    for(int i = 1; i <= n; i++) {
        if(!f[i])
            dfsctc(i, adj, topo);
    }
    f = 0;
    int cnt = 0;
    for(int i = n - 1; i >= 0; i--) {
        if(!f[topo[i]]) {
            aux.clear();
            cnt++;
            dfsctc(topo[i], inv, aux);
            for(auto x : aux) ///egalam ctc-urile
                ctc[x] = cnt;//, cout << x << " ";
            //cout << '\n';
        }
    }

    ///GASIM NOILE MUCHII PE CARE LE FOLOSIM
    for(int i = 1; i <= n; i++) {
        for(auto nod : adj[i]) {
            if(ctc[i] != ctc[nod])
                edges.insert({ctc[i], ctc[nod]});
        }
    }
    ///ORDONAM FRUMOS MUCHIILE
    v.resize(cnt + 1);
    inv.clear();
    inv.resize(cnt + 1);
    for(auto x : edges) {
        v[x.first].push_back(x.second);
        //inv[x.second].push_back(x.first);
        //cout << x.first << " " << x.second << '\n';
    }

    ///ALCATUIM ARBORELE
    f = 0;
    dfstree(1);

    /*for(int i = 1; i <= cnt; i++) {
        cout << i << " " << inv[i].size() << "\n";
    }*/

    f = 0; ///calculam aux-ul
    dfsaux(1);
    f = 0; ///calculam dp-ul
    dfsdp(1);

    /*for(int i = 1; i <= cnt; i++)
        cout << sub[i] << " ";
    cout << '\n';

    for(int i = 1; i <= cnt; i++) {
        for(int j = 0; j < LOG; j++)
            cout << dp[i][j] << " ";
        cout << '\n';
    }*/

    int q;
    cin >> q;
    while(q--) {
        int a, b;
        cin >> a >> b;
        a = ctc[a], b = ctc[b];
        int lca = LCA(a, b);
        //cout << a << " " << b << "  " << lca << '\n';
        cout << query(a, lca) << '\n';
    }
    return 0;
}