Cod sursa(job #3259629)

Utilizator Dani111Gheorghe Daniel Dani111 Data 27 noiembrie 2024 08:17:06
Problema Obiective Scor 5
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.23 kb
#include <bits/stdc++.h>
#include <unordered_set>
using namespace std;

const int MAX = 32e4;
int N, M;
vector<int>G[MAX + 3];
vector<int>Gt[MAX + 3];

unordered_set<int>Gctc[MAX + 3];
//traiesc cu speranta sincera ca toate astea intra in limita de memorie
vector<int>S;
int v[MAX + 3];
int v1[MAX + 3];
int cntctc;
int nr[MAX + 3];
int lvl[MAX + 3];
int up[MAX + 3][16];
int upp[MAX + 3][16];
int uparb[MAX + 3];
int uparbnod[MAX + 3];
vector<pair<int, int>>tree[MAX + 3];

void dfs(int nod) {
    v[nod] = 1;

    for(auto i : G[nod]) {
        if(!v[i]) {
            dfs(i);
        }
    }

    S.push_back(nod);
}

void dfs1(int nod) {
    v[nod] = cntctc;
    for(auto i : Gt[nod]) {
        if(!v[i]) {
            dfs1(i);
        }
    }

}

void dfs3(int nod, int parent = 0) {
    lvl[nod] = lvl[parent] + 1;
    uparb[nod] = lvl[parent];
    uparbnod[nod] = parent;

    for(auto i : tree[nod]) {

        if(i.first != parent && i.second == 1) {
            dfs3(i.first, nod);
            if(uparb[i.first] < uparb[nod]) {
                uparb[nod] = uparb[i.first];
                uparbnod[nod] = i.first;
            }
        }
        uparb[nod] = min(uparb[nod], lvl[i.first]);
        if(uparb[nod] > lvl[i.first]) {
            uparb[nod] = lvl[i.first];
            uparbnod[nod] = i.first;
        }
    }

}

void precalc(int nod, int parent = 0) {
    up[nod][0] = parent;
    upp[nod][0] = uparbnod[nod];
    for(int i = 1; i <= 15; i++) {
        up[nod][i] = up[up[nod][i - 1]][i - 1];
        upp[nod][i] = upp[upp[nod][i - 1]][i - 1];
    }

    for(auto i : tree[nod]) {
        if(i.first != parent && i.second == 1) {
            precalc(i.first, nod);
        }
    }

}

int lca(int a, int b) {
    int ans;
    if(lvl[a] < lvl[b]) swap(a, b);

    for(int i = 15; i >= 0; i--) {
        if(lvl[up[a][i]] >= lvl[b]) a = up[a][i];
    }

    if(a == b) return a;

    for(int i = 15; i >= 0; i--) {
        if(up[a][i] != up[b][i]) {
            a = up[a][i];
            b = up[b][i];
        }
    }
    return up[a][0];
}

int main() {
    freopen("obiective.in", "r", stdin);
    freopen("obiective.out", "w", stdout);

    cin.tie(0); cout.tie(0);
    ios_base::sync_with_stdio(false);

    cin >> N >> M;

    for(int i = 1; i <= M; i++) {
        int u, v;
        cin >> u >> v;

        G[u].push_back(v);
        Gt[v].push_back(u);
    }

    dfs(1);

    reverse(S.begin(), S.end());



    for(int i = 1; i <= N; i++) v[i] = 0;

    for(int i = 0; i < N; i++) {
        if(!v[S[i]]) {
            cntctc++;
            dfs1(S[i]);
        }
    }
    for(int i = 1; i <= N; i++) {

        for(auto j : G[i]) {

            if(v[i] != v[j]) {
                if(!Gctc[v[i]].count(v[j])) {
                    nr[v[j]]++;
                }

                Gctc[v[i]].insert(v[j]);

            }

        }

    }

    queue<int>q;

    for(int i = 1; i <= cntctc; i++) {
        if(nr[i] == 0) q.push(i);
    }

    while(!q.empty()) {
        for(auto i : Gctc[q.front()]) {
            nr[i]--;
            if(nr[i] != 0) {
                tree[i].push_back({q.front(), 0});
                tree[q.front()].push_back({i, 0});
            }
            else {
                tree[i].push_back({q.front(), 1});
                tree[q.front()].push_back({i, 1});
                q.push(i);
            }

        }

        q.pop();
    }
    dfs3(1);
    precalc(1);
    // for(int i = 1; i <= N; i++) {
    //     cout << uparb[i] << ' ';
    // }
    // cout << '\n';

    int Q; cin >> Q;
    while(Q--) {
        int x, y; cin >> x >> y;
        x = v[x]; y = v[y];

        int lca1 = lca(x, y);
        //cout << lvl[lca1] << ' ' << lvl[x] << ' ' << lvl[y] << '\n';
        if(x == y || lca1 == x) {
            cout << 0 << '\n';
            continue;
        }
        int ans = 0;
        for(int i = 15; i >= 0; i--) {
            //cout << upp[x][i] << ' ';
            if(lvl[upp[x][i]] > lvl[lca1]) {
                x = upp[x][i];
                ans += (1 << i);
            }
        }
        //cout << lvl[x] << ' ';
        cout << ans + 1 << '\n';
    }
}