Cod sursa(job #1291817)

Utilizator andreiiiiPopa Andrei andreiiii Data 13 decembrie 2014 12:10:07
Problema Obiective Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.75 kb
#include <algorithm>
#include <bitset>
#include <fstream>

using namespace std;

const int Nmax = 32005;

int N;
vector<int> G[Nmax], Gt[Nmax];
vector<int> G2[Nmax], Gt2[Nmax];
int Cc[Nmax], Cccnt = 0;
int Snodes[Nmax];
int F[16][Nmax], Father[16][Nmax], Lvl[Nmax];

vector<pair<int, int>> queries;

bitset<Nmax> used;

void Read() {
    ifstream fin("obiective.in");

    int M;
    fin >> N >> M;

    while (M--) {
        int x, y;
        fin >> x >> y;

        G[x].push_back(y);
        Gt[y].push_back(x);
    }

    fin >> M;
    while (M--) {
        int x, y;
        fin >> x >> y;
        queries.push_back({x, y});
    }

    fin.close();
}

void Dfs1(const int node) {
    used[node] = true;
    for (const int p: G[node])
        if (!used[p])
            Dfs1(p);
    Snodes[++Snodes[0]] = node;
}

void Dfs2(const int node) {
    used[node] = false;
    for (const int p: Gt[node])
        if (used[p])
            Dfs2(p);
    Cc[node] = Cccnt;
}

void getConexComponents() {
    for (int i = 1; i <= N; ++i)
        if (!used[i])
            Dfs1(i);
    for (int i = N; i; --i) {
        int node = Snodes[i];
        if (used[node]) {
            ++Cccnt;
            Dfs2(node);
        }
    }

    for (int i = 1; i <= N; ++i) {
        for (int p: G[i]) {
            if (Cc[i] != Cc[p]) {
                G2[Cc[i]].push_back(Cc[p]);
                Gt2[Cc[p]].push_back(Cc[i]);
            }
        }
    }

    for (int i = 1; i <= N; ++i) {
        sort(G2[i].begin(), G2[i].end());
        G2[i].erase(unique(G2[i].begin(), G2[i].end()), G2[i].end());
        sort(Gt2[i].begin(), Gt2[i].end());
        Gt2[i].erase(unique(Gt2[i].begin(), Gt2[i].end()), Gt2[i].end());
    }
}

void Dfs3(const int node) {
    used[node] = true;
    for (const int p: G2[node])
        if (!used[p])
            Dfs3(p);
    Snodes[++Snodes[0]] = node;
}

void sortConexComponents() {
    Snodes[0] = 0;
    for (int i = 1; i <= Cccnt; ++i)
        if (!used[i])
            Dfs3(i);
}

void buildAsc(int F[][Nmax]) {
    for (int k = 1; k < 16; ++k)
        for (int i = 1; i <= Cccnt; ++i)
            F[k][i] = F[k - 1][F[k - 1][i]];
}

void buildTree() {
    Lvl[0] = N + 1;
    Lvl[N + 1] = -1;
    for (int i = Cccnt; i > 0; --i) {
        int node = Snodes[i];
        F[0][node] = N + 1;
        for (const int p: Gt2[node]) {
            Lvl[node] = max(Lvl[node], Lvl[p] + 1);
            if (Lvl[p] < Lvl[Father[0][node]])
                Father[0][node] = p;
            if (Lvl[p] > Lvl[F[0][node]])
                F[0][node] = p;
        }
    }
    for (int i = 1; i <= Cccnt; ++i) {
        int node = Snodes[i];
        for (const int p: G2[node]) {
            if (Lvl[Father[0][p]] < Lvl[Father[0][node]])
                Father[0][node] = Father[0][p];
        }
    }
    F[0][Snodes[Cccnt]] = Father[0][Snodes[Cccnt]] = Snodes[Cccnt];
    buildAsc(F);
    buildAsc(Father);
}

void Solve() {
    getConexComponents();
    sortConexComponents();
    buildTree();
}

int getUp(int x, int y) {
    for (int k = 15; k >= 0; --k)
        if (y & (1 << k))
            x = F[k][x];
    return x;
}

int lca(int x, int y) {
    if (Lvl[x] < Lvl[y]) swap(x, y);
    x = getUp(x, Lvl[x] - Lvl[y]);
    if (x == y) return x;

    for (int k = 15; k >= 0; --k)
        if (F[k][x] != F[k][y])
            x = F[k][x], y = F[k][y];

    return F[0][x];
}

int Query(int n1, int n2) {
    int l = lca(n1, n2);
    if (l == n1) return 0;
    int cnt = 1;
    for (int k = 15; k >= 0; --k)
        if (Lvl[Father[k][n1]] > Lvl[l])
            n1 = Father[k][n1], cnt += (1 << k);
    return cnt;
}

void Write() {
    ofstream fout("obiective.out");
    for (const auto& p: queries)
        fout << Query(Cc[p.first], Cc[p.second]) << '\n';
    fout.close();
}

int main()
{
    Read();
    Solve();
    Write();
}