Cod sursa(job #878323)

Utilizator SpiderManSimoiu Robert SpiderMan Data 14 februarie 2013 12:23:57
Problema Obiective Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.66 kb
# include <algorithm>
# include <cassert>
# include <cstdio>
# include <cstring>
# include <map>
# include <set>
# include <vector>
using namespace std;

# define x first
# define y second

typedef pair <int, int> PR;
const char *FIN = "obiective.in", *FOU = "obiective.out";
const int MAX_N = 32005, MAX_M = 64005, MAX_NIV = 19;

PR obj[MAX_M];
bool viz[MAX_N];
int N, M, T, RAD, nrcomp, sq_len, P[MAX_N], grad[MAX_N], st[MAX_N], dr[MAX_N], niv[MAX_N], node[MAX_NIV][MAX_N];
vector <int> sol, G[MAX_N], Gn[MAX_N], Gt[MAX_N];
map <int, int> comp;
set <PR> SET;

void dfp (int P) { // marchez cu + graful G
    viz[P] = 1;
    for (vector <int> :: iterator it = Gn[P].begin (); it != Gn[P].end (); ++it)
        if (viz[*it] == 0)
            dfp (*it);
    sol.push_back (P);
}

void dfm (int P, int cat) { // marchez cu - graful transpus lui G
    viz[P] = 1, comp[P] = cat;
    for (vector <int> :: iterator it = Gt[P].begin (); it != Gt[P].end (); ++it)
        if (viz[*it] == 0)
            dfm (*it, cat);
}

void tareconexe (void) {
    for (int i = 1; i <= N; ++i)
        if (viz[i] == 0) dfp (i);
    memset (viz, 0, sizeof (viz));
    for (nrcomp = 0; sol.size (); sol.pop_back ()) // parcurg invers elementele care le-am parcurs in DF+
        if (viz[sol.back ()] == 0)
            dfm (sol.back (), ++nrcomp);
    for (int i = 1; i <= M; ++i) {
        obj[i] = make_pair (comp[obj[i].x], comp[obj[i].y]);
        if (obj[i].x != obj[i].y && SET.count (obj[i]) == 0) {
            G[obj[i].x].push_back (obj[i].y), grad[obj[i].y] += 1;
            SET.insert (obj[i]);
        }
    }
}

inline bool compare (const int &a, const int &b) {
    return P[a] < P[b];
}

void dfsT (int S) {
    viz[S] = 1;
    for (vector <int> :: iterator it = G[S].begin (); it != G[S].end (); ++it)
        if (viz[*it] == 0)
            dfsT (*it);
    sol.push_back (S);
}

void topologicals (void) {
    sol.clear (), memset (viz, 0, sizeof (viz));
    for (int i = 1; i <= nrcomp; ++i)
        if (viz[i] == 0) dfsT (i);
    reverse (sol.begin (), sol.end ());
    for (size_t i = 0; i < sol.size (); ++i)
        P[sol[i]] = i;
    for (int i = 1; i <= nrcomp; ++i)
        sort (G[i].begin (), G[i].end (), compare);
}

void dfsL (int S) {
    viz[S] = 1, st[S] = ++sq_len;
    for (vector <int> :: iterator it = G[S].begin (); it != G[S].end (); ++it)
        if (viz[*it] == 0)
            dfsL (*it);
    dr[S] = sq_len;
}

void liniarize (void) {
    memset (viz, 0, sizeof (viz)), dr[0] = 0x3f3f3f3f;
    for (int i = 1; i <= nrcomp; ++i)
        if (grad[i] == 0) {
            RAD = i, dfsL (i);
            break;
        }
}

void dfs1 (int S) {
    viz[S] = 1;
    for (vector <int> :: iterator it = G[S].begin (); it != G[S].end (); ++it)
        if (viz[*it]) {
            if (niv[*it] > niv[S]) node[0][*it] = S;
            niv[*it] = min (niv[*it], niv[S]);
        } else {
            niv[*it] = niv[S] + 1, node[0][*it] = S;
            dfs1 (*it);
            if (niv[*it] < niv[S])
                niv[S] = niv[*it], node[0][S] = node[0][*it];
        }
}

void dfs2 (int S) {
    viz[S] = 1;
    for (vector <int> :: iterator it = G[S].begin (); it != G[S].end (); ++it) {
        if (viz[*it] == 0) dfs2 (*it);
        if (niv[*it] < niv[S])
            niv[S] = niv[*it], node[0][S] = node[0][*it];
    }
}

void buildascensors () {
    memset (viz, 0, sizeof (viz)), dfs1 (RAD);
    memset (viz, 0, sizeof (viz)), dfs2 (RAD);
    for (int i = 1; i < MAX_NIV; ++i)
        for (int j = 1; j <= nrcomp; ++j)
            node[i][j] = node[i - 1][node[i - 1][j]];
}

inline bool ascensor (int a, int b) {
    return st[b] <= st[a] && dr[a] <= dr[b];
}

int main (void) {
    assert (freopen (FIN, "r", stdin));
    assert (freopen (FOU, "w", stdout));

    assert (scanf ("%d %d", &N, &M) == 2);
    for (int i = 1; i <= M; ++i) {
        assert (scanf ("%d %d", &obj[i].x, &obj[i].y) == 2);
        Gn[obj[i].x].push_back (obj[i].y);
        Gt[obj[i].y].push_back (obj[i].x);
    }
    tareconexe (), topologicals (), liniarize (), buildascensors ();
    for (assert (scanf ("%d", &T) == 1); T; --T) {
        int x, y;
        assert (scanf ("%d %d", &x, &y) == 2), x = comp[x], y = comp[y];
        if (x == y || ascensor (y, x))
            printf ("0\n");
        else {
            int solution = 0, nod = x;
            for (int i = MAX_NIV - 1; i + 1; --i)
                if (!ascensor (y, node[i][nod]))
                    nod = node[i][nod], solution += 1 << i;
            if (ascensor (y, node[0][nod])) solution += 1;
            printf ("%d\n", solution);
        }
    }
}