Cod sursa(job #3326566)

Utilizator Gabriel_DaescuDaescu Gabriel Florin Gabriel_Daescu Data 29 noiembrie 2025 14:11:15
Problema Obiective Scor 5
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 5.45 kb
#include <bits/stdc++.h>
using namespace std;

const int NMAX = 35002;

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

int N, M, T;
vector<int> graph[NMAX], graph_tr[NMAX];
int viz[NMAX];
stack<int> order_st;
int comp[NMAX], nrctc;

// graful condensat (temporar folosim unordered_map pentru deduplare si cost minim)
vector< unordered_map<int,int> > adjC; // adjC[i][j] = cost (0 sau 1)

// graful final al componentelor (vecini, cost)
vector<vector<pair<int,int>>> graph_ctc;

// date pentru LCA simplu si dist cost
int nivel[NMAX], tata[NMAX], distC[NMAX];

void citire() {
    fin >> N >> M;
    int u, v;
    for (int i = 0; i < M; ++i) {
        fin >> u >> v;
        graph[u].push_back(v);
        graph_tr[v].push_back(u);
    }
    fin >> T;
}

// DFS1 iterativ pentru a obține ordinea (finish times)
void kosaraju_first() {
    for (int i = 1; i <= N; ++i) viz[i] = 0;
    vector<int> it(NMAX, 0);
    for (int s = 1; s <= N; ++s) {
        if (viz[s]) continue;
        // stack of nodes
        vector<int> st;
        st.push_back(s);
        while (!st.empty()) {
            int node = st.back();
            if (!viz[node]) {
                viz[node] = 1;
                it[node] = 0;
            }
            bool pushed = false;
            while (it[node] < (int)graph[node].size()) {
                int nxt = graph[node][it[node]++];
                if (!viz[nxt]) {
                    st.push_back(nxt);
                    pushed = true;
                    break;
                }
            }
            if (!pushed) {
                // finished node
                order_st.push(node);
                st.pop_back();
            }
        }
    }
}

// DFS2 iterativ pe graful transpus pentru a marca componentele
void kosaraju_second() {
    for (int i = 1; i <= N; ++i) viz[i] = 1; // reuse: 1 = unprocessed in second pass
    nrctc = 0;
    while (!order_st.empty()) {
        int node = order_st.top(); order_st.pop();
        if (!viz[node]) continue;
        ++nrctc;
        // iterative DFS on transposed graph
        vector<int> st;
        st.push_back(node);
        viz[node] = 0; // processed
        comp[node] = nrctc;
        while (!st.empty()) {
            int x = st.back(); st.pop_back();
            for (int y : graph_tr[x]) {
                if (viz[y]) {
                    viz[y] = 0;
                    comp[y] = nrctc;
                    st.push_back(y);
                }
            }
        }
    }
}

int LCA_simple(int a, int b) {
    while (a != b) {
        if (nivel[a] > nivel[b]) a = tata[a];
        else b = tata[b];
    }
    return a;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    citire();

    // Kosaraju
    kosaraju_first();
    kosaraju_second();

    // Construct adjC (deduplicare, pastram cost minim)
    adjC.assign(nrctc + 1, unordered_map<int,int>());
    for (int u = 1; u <= N; ++u) {
        for (int v : graph[u]) {
            int cu = comp[u], cv = comp[v];
            if (cu == cv) continue;
            // muchia cu->cv cu cost 0 (directa)
            auto it = adjC[cu].find(cv);
            if (it == adjC[cu].end()) adjC[cu][cv] = 0;
            else it->second = min(it->second, 0);
            // inversa cv->cu cu cost 1
            auto it2 = adjC[cv].find(cu);
            if (it2 == adjC[cv].end()) adjC[cv][cu] = 1;
            else it2->second = min(it2->second, 1);
        }
    }

    // Convertim in vector de vectori pentru iterare rapida
    graph_ctc.assign(nrctc + 1, vector<pair<int,int>>());
    for (int i = 1; i <= nrctc; ++i) {
        graph_ctc[i].reserve(adjC[i].size());
        for (auto &p : adjC[i]) {
            graph_ctc[i].push_back({p.first, p.second});
        }
    }

    // Initializari pentru tata/nivel/dist
    for (int i = 1; i <= nrctc; ++i) {
        tata[i] = 0;
        nivel[i] = 0;
        distC[i] = 0;
    }

    // Parcurgem (iterativ) fiecare componenta conexa neorientata (sigur e una, dar pentru siguranta)
    for (int start = 1; start <= nrctc; ++start) {
        if (tata[start] != 0) continue; // deja vizitat
        // BFS/DFS iterative (folosim stack)
        stack<int> st;
        tata[start] = start;
        nivel[start] = 0;
        distC[start] = 0;
        st.push(start);
        while (!st.empty()) {
            int x = st.top(); st.pop();
            for (auto &pr : graph_ctc[x]) {
                int y = pr.first;
                int cost = pr.second;
                if (tata[y] == 0) {
                    tata[y] = x;
                    nivel[y] = nivel[x] + 1;
                    distC[y] = distC[x] + cost;
                    st.push(y);
                }
            }
        }
    }

    // Raspuns la interogari
    for (int i = 0; i < T; ++i) {
        int g, m;
        fin >> g >> m;
        int cg = comp[g], cm = comp[m];
        if (cg == cm) {
            fout << 0 << '\n';
            continue;
        }
        int l = LCA_simple(cg, cm);
        // cost de la L la B (in jos) + cost de la A la L cand urcam (1 - cost_injos)
        int cost_L_to_B = distC[cm] - distC[l];
        int up_edges_A_to_L = nivel[cg] - nivel[l];
        int cost_A_to_L_when_up = up_edges_A_to_L - (distC[cg] - distC[l]);
        int ans = cost_L_to_B + cost_A_to_L_when_up;
        fout << ans << '\n';
    }

    fin.close();
    fout.close();
    return 0;
}