Cod sursa(job #908434)

Utilizator mlupseLupse-Turpan Mircea mlupse Data 9 martie 2013 13:53:52
Problema Obiective Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 6.65 kb
#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>

using namespace std;

#define CLEAR(x) memset(x, 0, sizeof(x))
#define NMax 32768

int N, M, uz[NMax], timp[NMax], t, ctc, comp[NMax], rad;
int up[16][NMax], nivel[NMax], lg[NMax], bst;
int get_high[16][NMax], highest[NMax], dep[NMax], t_in[NMax], t_out[NMax];
vector<int> G[NMax], GT[NMax];

int cmp_nodes(const int& a, const int& b)//Functia pentru sortarea listelor de adiacenta in functie de sortarea topologica
{ return t_out[a] > t_out[b]; }

void df1(int nod)// Primul DFS (Kosaraju) pentru determinarea CTC
{
    int i, sz, x;

    uz[nod] = 1;
    for (sz = G[nod].size(), i = 0; i < sz; ++i)
        if (!uz[x = G[nod][i]])
            df1(x);
    timp[++t] = nod;
}

void df2(int nod)// Al doilea DFS (Kosaraju) pentru determinarea CTC
{
    int i, size, x;

    uz[nod] = 1; comp[nod] = ctc;
    for (size = GT[nod].size(), i = 0; i < size; ++i)
        if (!uz[x = GT[nod][i]])
            df2(x);
}

int det_root(void)//Determinarea radacinii lui G* (nodul cu gradul de intrare 0)
{
    int i, j, sz;

    CLEAR(uz);
    for (i = 1; i <= N; ++i)
        for (sz = GT[i].size(), j = 0; j < sz; ++j)
            uz[GT[i][j]] = 1;
    for (i = 1; i <= N; ++i)
        if (!uz[i])
            return i;
    return -1; // should never arrive here
}

void df_time(int nod)//Sortarea Topologica a lui G*
{
    int i, sz, x;

    uz[nod] = 1;
    for (sz = GT[nod].size(), i = 0; i < sz; ++i)
        if (!uz[x = GT[nod][i]])
            df_time(x);
    t_out[nod] = (++t);
}

void df3(int nod)//Se construieste vectorul de nivel si vectorul de tati(puteri a lui 2) pentru fiecare nod
{
    int i, sz, x;

    uz[nod] = 1;
    for (i = 0; ; ++i)
    {
        if (!up[i][ up[i][nod] ]) break;
        up[i+1][nod] = up[i][ up[i][nod] ];
    }

    for (sz = GT[nod].size(), i = 0; i < sz; ++i)
        if (!uz[x = GT[nod][i]])
        {
            up[0][x] = nod;
            nivel[x] = nivel[nod] + 1;
            df3(x);
        }
}

int LCA(int x, int y)
{
    for (; nivel[x] > nivel[y]; x = up[ lg[nivel[x]-nivel[y]] ][x]);
    for (; nivel[y] > nivel[x]; y = up[ lg[nivel[y]-nivel[x]] ][y]);
    if (x == y) return x;

    int log;
    for (log = lg[nivel[x]]; log >= 0; --log)
        if (up[log][x] != up[log][y])
            x = up[log][x],
            y = up[log][y];
    if (x != y) x = up[0][x];
    return x;
}

void df4(int nod)
{
    int i, sz, x;

    uz[nod] = 1;
    for (sz = GT[nod].size(), i = 0; i < sz; ++i)
        if (!uz[x = GT[nod][i]])
        {
            df4(x);
            if (nivel[ highest[x] ] < nivel[ highest[nod] ])
                highest[nod] = highest[x];
        }
}

void df5(int nod)
{
    int i, sz, x;

    for (i = 0; ; ++i)
    {
        if (!get_high[i][ get_high[i][nod] ]) break;
        get_high[i+1][nod] = get_high[i][ get_high[i][nod] ];
    }

    uz[nod] = 1;
    for (sz = G[nod].size(), i = 0; i < sz; ++i)
        if (!uz[x = G[nod][i]])
        {
            get_high[0][x] = nod;
            dep[x] = dep[nod] + 1;
            df5(x);
        }
}

void df6(int nod)
{
    int i, sz, x;

    uz[nod] = 1; t_in[nod] = (++t);
    for (sz = GT[nod].size(), i = 0; i < sz; ++i)
        if (!uz[x = GT[nod][i]])
            df6(x);
    t_out[nod] = (++t);
}

int stramos(int x, int y)
{ return t_in[x] <= t_in[y] && t_out[y] <= t_out[x]; }

int main(void)
{
    int T, i, j, k, sz, log;

    freopen("obiective.in", "r", stdin);
    freopen("obiective.out", "w", stdout);
//Citire
    scanf("%d %d", &N, &M);
    for (; M; --M)
    {
        scanf("%d %d", &i, &j);
        G[i].push_back(j);//Construire Graf
        GT[j].push_back(i);//Construire Graf Transpus (pentru Kosaraju)
    }
//Primul DFS pentru CTC (Kosaraju) Se construieste vectorul de timpi timp[i] pentru DFS 2

    for (i = 1; i <= N; ++i)
        if (!uz[i])
            df1(i);
//Al doilea DFS pentru CTC (Kosaraju) Se stabileste pentru fiecare nod carei componente conexe ii apartine comp[nod]
        CLEAR(uz);// Componentele conexe sunt in ordinea sortarii topologice datorita DFS 1
    for (i = N; i; --i)
        if (!uz[j = timp[i]])
        {
            ++ctc;
            df2(j);
        }

    for (i = 1; i <= N; ++i)//Se refoloseste GT pentru a forma graful G* (graful componentelor tare conexe)
        GT[i].clear();
    for (i = 1; i <= N; ++i)
        for (sz = G[i].size(), j = 0; j < sz; ++j)//GT va contine doar muchiile dintre componentele tare conexe
            if (comp[i] != comp[G[i][j]])//Fiecarui nod x din G ii corespunde nodul comp[x] din GT
                GT[comp[i]].push_back( comp[G[i][j]] );//Astfel GT are N=ctc noduri
    N = ctc;
    //rad = det_root(); //Se afla radacina lui G* (nodul care are gradul de intrare 0)
    rad=1;
    t = 0;
    CLEAR(uz);
    df_time(rad);//Sortarea Topologica a lui G(G este aciclic) pornind din radacina rad
    for (i = 1; i <= N; ++i)//Se sorteaza listele de adiacenta conform sortarii topologice DF_TIME
        sort(GT[i].begin(), GT[i].end(), cmp_nodes);

    CLEAR(uz);
    df3(rad);//Se construieste vectorul up (tatii puteri ai lui 2) pentru fiecare nod
    for (i = 2; i< NMax; ++i)
        lg[i] = lg[i/2]+1;

    for (i = 1; i <= N; ++i)//Se initializeaza vectorul highest cu vectorul de tati
        highest[i] = up[0][i];

    for (i = 1; i <= N; ++i)
        for (sz = GT[i].size(), j = 0; j < sz; ++j)
            if (up[0][ GT[i][j] ] != i)
            {
                if (nivel[i] < nivel[ highest[ GT[i][j] ] ])
                    highest[ GT[i][j] ] = i;
            }
    CLEAR(uz);
    df4(rad);

    for (i = 1; i <= N; ++i)//Refolosesc G pentru a construi arborele final
        G[i].clear();
    for (i = 1; i <= N; ++i)
    {
        if (!highest[i]) continue;
        G[highest[i]].push_back(i);//Vectorul highest este vectorul de tati pentru arbore
    }
    CLEAR(uz);
    df5(rad);

    t = 0;
    CLEAR(uz);
    CLEAR(t_out);
    df6(rad);

    for (scanf("%d", &T); T; --T)
    {
        scanf("%d %d", &i, &j);
        i = comp[i]; j = comp[j];
        if (i == j)
        {
            printf("0\n");
            continue;
        }

        k = LCA(i, j);
        if (i == k)
        {
            printf("0\n");
            continue;
        }
        j = i;
        for (log = lg[dep[i]]; log >= 0; --log)
        {
            if (!get_high[log][i]) continue;
            if (stramos(get_high[log][i], k)) continue;
            i = get_high[log][i];
        }

        printf("%d\n", dep[j] - dep[i] + 1);
    }

    return 0;
}