Cod sursa(job #663633)

Utilizator a_h1926Heidelbacher Andrei a_h1926 Data 18 ianuarie 2012 19:49:55
Problema Obiective Scor 5
Compilator cpp Status done
Runda Lista lui wefgef Marime 5.11 kb
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>

#define NMax 100005
#define LogMax 18

using namespace std;

vector <int> G[NMax], GT[NMax];
int N, TSort[NMax], SCC[NMax], Root;
int A[LogMax][NMax], Log2[NMax], Level[NMax], HA[LogMax][NMax];
bool Used[NMax];

inline void DFP (int X)
{
    Used[X]=true;
    for (unsigned i=0; i<G[X].size (); ++i)
    {
        int V=G[X][i];
        if (!Used[V])
        {
            DFP (V);
        }
    }
    TSort[++TSort[0]]=X;
}

inline void DFM (int X)
{
    SCC[X]=SCC[0];
    for (unsigned i=0; i<GT[X].size (); ++i)
    {
        int V=GT[X][i];
        if (SCC[V]==0)
        {
            DFM (V);
        }
    }
}

void Kosaraju ()
{
    for (int i=1; i<=N; ++i)
    {
        if (!Used[i])
        {
            DFP (i);
        }
    }
    for (int i=TSort[0]; i>0; --i)
    {
        if (SCC[TSort[i]]==0)
        {
            ++SCC[0];
            DFM (TSort[i]);
        }
    }
}

inline void DFT (int X)
{
    Used[X]=true;
    for (unsigned i=0; i<GT[X].size (); ++i)
    {
        int V=GT[X][i];
        if (!Used[V])
        {
            DFT (V);
        }
    }
    TSort[X]=++TSort[0];
}

inline bool Compare (int a, int b)
{
    return TSort[a]>TSort[b];
}

void BuildNewG ()
{
    for (int i=1; i<=N; ++i)
    {
        GT[i].clear ();
    }
    memset (Used, 0, sizeof (Used));
    for (int X=1; X<=N; ++X)
    {
        for (unsigned i=0; i<G[X].size (); ++i)
        {
            int V=G[X][i];
            if (SCC[X]!=SCC[V])
            {
                GT[SCC[X]].push_back (SCC[V]);
                Used[SCC[V]]=true;
            }
        }
    }
    for (int X=1; X<=SCC[0]; ++X)
    {
        if (!Used[X])
        {
            Root=X;
            break;
        }
    }
    memset (Used, 0, sizeof (Used));
    memset (TSort, 0, sizeof (TSort));
    DFT (Root);
    for (int X=1; X<=SCC[0]; ++X)
    {
        sort (GT[X].begin (), GT[X].end (), Compare);
    }
}

inline void DFA (int X)
{
    for (int i=1; ; ++i)
    {
        A[i][X]=A[i-1][A[i-1][X]];
        if (A[i][X]==0)
        {
            break;
        }
    }
    for (unsigned i=0; i<GT[X].size (); ++i)
    {
        int V=GT[X][i];
        if (Level[V]==0)
        {
            A[0][V]=X;
            Level[V]=Level[X]+1;
            DFA (V);
        }
    }
}

void BuildAncestor ()
{
    for (int i=2; i<=N; ++i)
    {
        Log2[i]=Log2[i/2]+1;
    }
    Level[Root]=1;
    DFA (Root);
}

inline void DFH (int X)
{
    Used[X]=true;
    for (unsigned i=0; i<GT[X].size (); ++i)
    {
        int V=GT[X][i];
        if (!Used[V])
        {
            DFH (V);
            if (Level[HA[0][V]]<Level[HA[0][X]])
            {
                HA[0][X]=HA[0][V];
            }
        }
    }
    for (int i=1; ; ++i)
    {
        HA[i][X]=HA[i-1][HA[i-1][X]];
        if (HA[i][X]==0)
        {
            break;
        }
    }
}

void BuildHighest ()
{
    for (int i=1; i<=SCC[0]; ++i)
    {
        HA[0][i]=A[0][i];
    }
    for (int X=1; X<=SCC[0]; ++X)
    {
        for (unsigned i=0; i<GT[X].size (); ++i)
        {
            int V=GT[X][i];
            if (Level[X]<Level[HA[0][V]])
            {
                HA[0][V]=X;
            }
        }
    }
    memset (Used, 0, sizeof (Used));
    DFH (Root);
    for (int i=1; i<=Log2[N]; ++i)
    {
        for (int j=1; j<=SCC[0]; ++j)
        {
            HA[i][j]=HA[i-1][HA[i-1][j]];
        }
    }
}

inline int LCA (int X, int Y)
{
    for (; Level[X]>Level[Y]; X=A[Log2[Level[X]-Level[Y]]][X]);
    for (; Level[X]<Level[Y]; Y=A[Log2[Level[Y]-Level[X]]][Y]);
    if (X==Y)
    {
        return X;
    }
    for (int Step=Log2[Level[X]]+1; Step>=0; --Step)
    {
        if (A[Step][X]!=A[Step][Y])
        {
            X=A[Step][X];
            Y=A[Step][Y];
        }
    }
    if (X!=Y)
    {
        X=A[0][X];
    }
    return X;
}

void Solve ()
{
    Kosaraju ();
    BuildNewG ();
    BuildAncestor ();
    BuildHighest ();
}

void Read ()
{
    freopen ("obiective.in", "r", stdin);
    int M;
    scanf ("%d %d", &N, &M);
    for (; M>0; --M)
    {
        int X, Y;
        scanf ("%d %d", &X, &Y);
        G[X].push_back (Y);
        GT[Y].push_back (X);
    }
}

inline int Query (int X, int Y)
{
    int Q=0;
    for (int Step=Log2[Level[X]]+1; Step>=0; --Step)
    {
        if (Level[HA[Step][X]]<=Level[Y])
        {
            Q=Step;
        }
        else
        {
            X=HA[Step][X];
        }
    }
    return Q+1;
}

void Print ()
{
    freopen ("obiective.out", "w", stdout);
    int M;
    scanf ("%d", &M);
    for (; M>0; --M)
    {
        int X, Y;
        scanf ("%d %d", &X, &Y);
        X=SCC[X], Y=SCC[Y];
        int Z=LCA (X, Y);
        if (X==Y or X==Z)
        {
            printf ("0\n");
            continue;
        }
        printf ("%d\n", Query (X, Z));
    }
}

int main ()
{
    Read ();
    Solve ();
    Print ();
    return 0;
}