Cod sursa(job #67949)

Utilizator dominoMircea Pasoi domino Data 26 iunie 2007 01:29:56
Problema Obiective Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.19 kb
#include <stdio.h>
#include <algorithm>
#include <vector>

using namespace std;

#define MAX_LG 15
#define MAX_N 30005
#define FIN "obiective.in"
#define FOUT "obiective.out"
#define mp make_pair 
#define pb push_back
#define f first
#define s second

typedef vector<int> VI;

int N, M, NT, lev[MAX_N], lg[MAX_N], comp[MAX_N], stk[MAX_N], stk_len, pos[MAX_N], ncomp, up[MAX_LG][MAX_N];
VI G[MAX_N], GT[MAX_N], GC[MAX_N]; char U[MAX_N];
pair<int, int> T[MAX_LG][MAX_N];

void DFS1(int n)
{
    VI::iterator it;

    U[n] = 1;
    for (it = G[n].begin(); it != G[n].end(); it++)
        if (!U[*it]) DFS1(*it);
    stk[stk_len++] = n;
}

void DFS2(int n, int c)
{
    VI::iterator it;

    U[n] = 1; comp[n] = c;
    for (it = GT[n].begin(); it != GT[n].end(); it++)
        if (!U[*it]) DFS2(*it, c);
}

void DFS3(int n)
{
    VI::iterator it;

    U[n] = 1;
    for (it = GC[n].begin(); it != GC[n].end(); it++)
        if (!U[*it]) DFS3(*it);
    stk[stk_len++] = n;
    pos[n] = stk_len;
}

inline bool cmp(int i, int j)
{
    return pos[i] > pos[j];
}

void DFS4(int n)
{
    VI::iterator it;
    int i;

    U[n] = 1;
    for (i = 1; i <= lg[lev[n]]; i++)
        up[i][n] = up[i-1][up[i-1][n]];

    sort(GC[n].begin(), GC[n].end(), cmp);
    for (it = GC[n].begin(); it != GC[n].end(); it++)
    {
        if (!U[*it])
        {
            lev[*it] = lev[n]+1;
            up[0][*it] = n;
            T[0][*it] = mp(lev[n], n);
            DFS4(*it);
        }
        else T[0][*it] = min(T[0][*it], mp(lev[n], n));
    }
}

void DFS5(int n)
{
    VI::iterator it;

    U[n] = 1;
    for (it = GC[n].begin(); it != GC[n].end(); it++)
    {
        if (U[*it]) continue;
        DFS5(*it);
        T[0][n] = min(T[0][n], T[0][*it]);
    }
}

void DFS6(int n)
{
    VI::iterator it;
    int i;

    U[n] = 1;
    for (i = 1; i <= lg[lev[n]]; i++)
        T[i][n] = T[i-1][T[i-1][n].s];

    for (it = GC[n].begin(); it != GC[n].end(); it++)
        if (!U[*it]) DFS6(*it);
}

int LCA(int i, int j)
{
    int k;

    while (lev[i] > lev[j]) i = up[lg[lev[i]-lev[j]]][i];
    while (lev[i] < lev[j]) j = up[lg[lev[j]-lev[i]]][j];
    if (i == j) return i;
    for (k = lg[lev[i]]; k >= 0; k--)
    {
        if (up[k][i] == up[k][j]) continue;
        i = up[k][i]; j = up[k][j];
    }
    return up[0][i];
}

int main(void)
{
    int i, j, x, y, n, ret;
    VI::iterator it;

    freopen(FIN, "r", stdin);
    freopen(FOUT, "w", stdout);

    for (i = 1, j = 0; i < MAX_N; i++)
    {
        lg[i] = j;
        if (i+1 == 1<<(j+1)) j++;
    }

    scanf("%d %d", &N, &M);
    for (; M; M--)
    {
        scanf("%d %d", &i, &j);
        G[i].pb(j); GT[j].pb(i);
    }

    // strongly connected components
    for (i = 1; i <= N; i++)
        if (!U[i]) DFS1(i);
    fill(U+1, U+N+1, 0);
    for (i = stk_len-1; i >= 0; i--)
        if (!U[stk[i]]) DFS2(stk[i], ++ncomp);

    // build SCC graph
    for (i = 1; i <= N; i++)
        for (it = G[i].begin(); it != G[i].end(); it++)
        {
            if (comp[i] == comp[*it]) continue;
            GC[comp[i]].pb(comp[*it]);
        }

    // topological sort 
    stk_len = 0;
    fill(U+1, U+ncomp+1, 0);
    for (i = 1; i <= ncomp; i++)
        if (!U[i]) DFS3(i);

    // build LCA pointers and up pointers
    fill(U+1, U+ncomp+1, 0);
    for (i = stk_len-1; i >= 0; i--)
        if (!U[stk[i]]) 
        {
            T[0][stk[i]] = mp(0, stk[i]);
            up[0][stk[i]] = stk[i];
            DFS4(stk[i]);
        }

    // build up pointers with powers of 2
    fill(U+1, U+ncomp+1, 0);
    for (i = stk_len-1; i >= 0; i--)
        if (!U[stk[i]]) DFS5(stk[i]);
    fill(U+1, U+ncomp+1, 0);
    for (i = stk_len-1; i >= 0; i--)
        if (!U[stk[i]]) DFS6(stk[i]);

    for (scanf("%d", &NT); NT; NT--)
    {
        scanf("%d %d", &x, &y);
        x = comp[x]; y = comp[y];
        n = LCA(x, y);
        if (n == x) { printf("0\n"); continue; }
        ret = 0;
        for (i = lg[lev[x]]; i >= 0; i--)
            if (T[i][x].f > lev[n]) { ret += 1<<i; x = T[i][x].s; }
        printf("%d\n", ret+1);
    }

    return 0;
}