Cod sursa(job #3301347)

Utilizator iulia_morariuIuli Morariu iulia_morariu Data 24 iunie 2025 23:42:33
Problema Obiective Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 5.25 kb
#include <algorithm>
#include <iostream>
#include <fstream>
#include <climits>
#include <vector>
#include <stack>
#include <cmath>
#include <set>
// #include <bits/stdc++.h>
#define in  fin
#define out fout

using namespace std;

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

vector<int> g[32000], gt[32000];
vector<int> st;
bool mr[32000];
vector< vector<int> > ctc;
int comp[32000];

void dfs1(int nod){
    mr[nod] = 1;
    for(const int &x : g[nod]){
        if(mr[x]) continue;
        dfs1(x);
    }
    st.push_back(nod);
}

void dfs2(int nod){
    mr[nod] = 1;
    comp[nod] = ctc.size() - 1;
    ctc.back().push_back(nod);
    for(const int &x : gt[nod]){
        if(mr[x]) continue;
        dfs2(x);
    }
}

int d[32000]; // de cati oameni depinde
void build_copac(int nod){
    set<int> pun;
    for(const int &x : gt[nod]){
        d[x]--;
        if(d[x] == 0) pun.insert(x);
        else g[x].push_back(nod);
    }
    for(const auto &x : pun){
        g[nod].push_back(x);
        build_copac(x);
    }
}

int rmq[32000][16];
int niv[32000];
int start;

void dfs_nivel(int nod, int f){
    // cerr << "nod = " << nod << '\n';
    rmq[nod][0] = f;
    for(const int &x : g[nod]){
        if(niv[x] != 0 || x == 0) continue;
        niv[x] = niv[nod] + 1;
        dfs_nivel(x, nod);
    }
}

void fa_rmq(){
    for(int j = 1; (1 << j) < ctc.size(); j++){
        for(int i = 0; i < ctc.size(); i++){
            rmq[i][j] = rmq[ rmq[i][j - 1] ][j - 1];
        }
    }
}

int LCA(int a, int b){
    if(niv[a] < niv[b]) swap(a, b);
    for(int l = 15; l >= 0; l--){
        if(niv[ rmq[a][l] ] >= niv[b]) a = rmq[a][l];
    }

    // cout << "ini a = " << a << " b = " << b << '\n';

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

int rmq2[32000][16]; // asta e pt queriuri, celalalt era pt lca-uri

void calc_rmq_2(int nod, int f){
    for(const int &x : g[nod]){
        if(x != f && niv[rmq2[nod][0]] > niv[x]){ // e back-edge
            rmq2[nod][0] = x;
        }else if(niv[x] == niv[nod] + 1){
            calc_rmq_2(x, nod);
            if(niv[ rmq2[x][0] ] < niv[ rmq2[nod][0] ]) rmq2[nod][0] = rmq2[x][0];
        }
    }
}

void precalc_rmq2(){ // ca la rmq1 basically
    for(int i = 0; i < ctc.size(); i++){
        rmq2[i][0] = rmq[i][0];
    }
    calc_rmq_2(start, -1);
    for(int j = 1; (1 << j) < ctc.size(); j++){
        for(int i = 0; i < ctc.size(); i++){
            rmq2[i][j] = rmq2[ rmq2[i][j - 1] ][j - 1];
        }
    }
}

int query(int a, int b){ // vreau sa ajung cu b peste lca dintre a si b
    // cout << "Am nevoie sa fac intre " << a << " si " << b << '\n';
    // cout << "  -- > comp : " << comp[a] << " si " << comp[b] << '\n';
    a = comp[a]; b = comp[b];
    int lca = LCA(a, b);

    // cout << "  -- > lca = " << lca << '\n';

    int sol = 0;
    for(int l = 15; l >= 0; l--){
        if(niv[ rmq2[a][l] ] > niv[lca]){
            sol += (1 << l);
            a = rmq2[a][l];
        }
    }
    if(niv[a] > niv[lca]){
        a = rmq[a][0]; sol++;
    }
    // cout << "  -- > sol = " << sol << '\n';
    // cout << "  -- > a = " << a << " b = " << b << '\n';
    return sol;
}

signed main(){
    ios_base::sync_with_stdio(false);
    in.tie(NULL);

    int n, m; in >> n >> m;
    for(int i = 0; i < m; i++){
        int a, b; in >> a >> b;
        a--; b--;
        g[a].push_back(b);
        gt[b].push_back(a);
    }

    for(int i = 0; i < n; i++){
        if(!mr[i]) dfs1(i);
    }
    for(int i = 0; i < n; i++) mr[i] = 0;
    for(int i = st.size() - 1; i >= 0; i--){
        if(!mr[st[i]]){
            ctc.push_back({});
            dfs2(st[i]);
        }
    }

    // cout << "St : ";
    // for(int i = 0; i < st.size(); i++) cout << st[i] << " ";
    // cout << '\n';

    // cout << "ctc : \n";
    // for(int i = 0; i < (int)ctc.size(); i++){
    //     for(const int &x : ctc[i]) cout << x << " ";
    //     cout << '\n';
    // }
    // acum condensam graful

    set< pair<int, int> > ne; // new edges
    for(int i = 0; i < n; i++){
        for(const int &j : g[i]){
            if(comp[i] != comp[j]){
                ne.insert( make_pair(comp[i], comp[j]) );
                // cout << "Trag muchie intre " << i << " si " << j << " ( " << comp[i] << " si " << comp[j] << " )\n";
            }
        }
        g[i].clear();
        gt[i].clear();
    }

    // cout << "new graf : \n";
    for(const auto &x : ne){
        // cout << x.first << " " << x.second << '\n';
        gt[x.first].push_back(x.second);
        d[x.second]++;
    }

    start = 0;
    for(int i = 0; i < ctc.size(); i++){
        if(d[i] == 0){ start = i; break; }
    }
    build_copac(start);

    // cout << "copac : \n";
    // for(int i = 0; i < n; i++){
    //     for(int j = 0; j < g[i].size(); j++){
    //         cout << "( " << i << " , " << g[i][j] << " )\n";
    //     }
    // }

    dfs_nivel(start, 0);
    fa_rmq();
    precalc_rmq2();

    // cout << "start = " << start << '\n';
    // cout << LCA(4, 3) << '\n';

    int q; in >> q;
    for(int i = 0; i < q; i++){
        int a, b; in >> a >> b;
        a--; b--;
        out << query(a, b) << '\n';
    }

    return 0;
}

/*
5 5
1 2
1 3
3 4
1 4
4 5
0

8 9
8 1
8 2
1 4
8 4
4 5
2 3
3 7
3 6
2 7
3
1 7
4 8
4 1
*/