Cod sursa(job #1044835)

Utilizator tzipleatudTudor Tiplea tzipleatud Data 30 noiembrie 2013 15:19:28
Problema Obiective Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 5.41 kb
/**
 Ideea pleaca de la observatia ca "Pentru orientarea initiala a strazilor, se garanteaza ca oricum am alege
 3 intersectii A, B, C, astfel incat sa putem ajunge din A in C si din B in C, atunci putem ajunge fie din A in B,
 fie din B in A ( posibil ambele )"

 Asta imi garanteaza ca, dupa ce fac graful CTC, acesta va arata ca un arbore + niste muchii inainte (adica nu am muchii transversale)
 Acum ca sa ajung din a in b trebuie sa ajung din a cat mai rapid in lca(a, b) sau mai sus de el (pentru ca daca ajung mai sus pot sa
 cobor pe muchii care exista deja, deci nu imi afecteaza costul).
 Imi pot face un greedy upmost[k][i] - nivelul minim (cat mai sus) pe care pot sa ajung din i in 1 << k pasi, iar apoi pot sa caut binar
 asemenator cu LCA cu stramosi.
*/


#include <fstream>
#include <vector>
#include <algorithm>
#include <stack>
#define NM 32010
#define LOGM 16

using namespace std;

ifstream f("obiective.in");
ofstream g("obiective.out");

int N, C, M, T, K;
int Level[NM], MinLevel[NM];
int WComponent[NM];
bool InStack[NM], NotRoot[NM];
vector<int> GI[NM], G[NM], GInverse[NM];
stack<int> S;
int Ancestors[LOGM][NM], UpMost[LOGM][NM];
int Depth[NM], MinDepth[NM];

void Read ()
{
    f >> N >> M;
    for (int i=1; i<=M; i++)
    {
        int a, b;
        f >> a >> b;
        GI[a].push_back(b);
    }
}

void DoTarjan (int node)
{
    MinLevel[node]=Level[node]=++K;
    S.push(node);
    InStack[node]=1;

    for (vector<int>::iterator it=GI[node].begin(); it!=GI[node].end(); ++it)
        if (!Level[*it])
        {
            DoTarjan(*it);
            MinLevel[node]=min(MinLevel[node], MinLevel[*it]);
        }
        else
        {
            if (InStack[*it])
                MinLevel[node]=min(MinLevel[node], MinLevel[*it]);
        }

    if (MinLevel[node]==Level[node])
    {
        ++C;

        for (; !S.empty(); )
        {
            int cnode=S.top();
            WComponent[cnode]=C;
            S.pop();
            InStack[cnode]=0;
            if (cnode==node)
                break;
        }
    }
}

void CTC ()
{
    for (int i=1; i<=N; i++)
        if (!Level[i])
            DoTarjan(i);

    for (int i=1; i<=N; i++)
        for (vector<int>::iterator it=GI[i].begin(); it!=GI[i].end(); ++it)
            if (WComponent[i]!=WComponent[*it])
            {
                G[WComponent[i]].push_back(WComponent[*it]);
                NotRoot[WComponent[*it]]=1;
            }

    for (int i=1; i<=C; i++)
    {
        sort(G[i].begin(), G[i].end());
        G[i].resize(unique(G[i].begin(), G[i].end())-G[i].begin());
        for (vector<int>::iterator it=G[i].begin(); it!=G[i].end(); ++it)
            GInverse[*it].push_back(i);
    }
}

void DFInverse (int node)
{
    int pos=0;
    MinDepth[node]=NM;
    for (vector<int>::iterator it=GInverse[node].begin(); it!=GInverse[node].end(); ++it)
    {
        if (!Depth[*it])
            DFInverse(*it);
        if (Depth[*it]>Depth[node])
        {
            Depth[node]=Depth[*it];
            pos=*it;
        }
        MinDepth[node]=min(MinDepth[node], MinDepth[*it]);
    }

    if (MinDepth[node]==NM)
        MinDepth[node]=0;
    MinDepth[node]++;
    Depth[node]++;
    Ancestors[0][node]=pos;
}

void DF (int node)
{
    for (vector<int>::iterator it=G[node].begin(); it!=G[node].end(); ++it)
    {
        if (!UpMost[0][*it])
            DF(*it);
        if (Depth[UpMost[0][*it]]<Depth[UpMost[0][node]])
            UpMost[0][node]=UpMost[0][*it];
    }

    for (vector<int>::iterator it=GInverse[node].begin(); it!=GInverse[node].end(); ++it)
        if (Depth[*it]<Depth[UpMost[0][node]])
            UpMost[0][node]=*it;
}

void BuildAncestors ()
{
    for (int i=1; i<=C; i++)
        if (!Depth[i])
            DFInverse(i);

    Depth[0]=NM;
    for (int i=1; i<=C; i++)
        if (!UpMost[0][i])
            DF(i);

    for (int j=1; (1 << j)<=C; j++)
        for (int i=1; i<=C; i++)
        {
            Ancestors[j][i]=Ancestors[j-1][Ancestors[j-1][i]];
            UpMost[j][i]=UpMost[j-1][UpMost[j-1][i]];
        }
}

int LCA (int a, int b)
{
    if (Depth[a]>Depth[b])
        swap(a, b);

    int log1, log2, k;
    for (log1=0; (1 << log1)<Depth[a]; ++log1);
    for (log2=0; (1 << log2)<Depth[b]; ++log2);

    for (k=log2; k>=0; k--)
        if (Depth[b]-(1 << k)>=Depth[a])
            b=Ancestors[k][b];

    if (a==b) return a;

    for (k=log1; k>=0; k--)
        if (Ancestors[k][a]!=0 && Ancestors[k][a]!=Ancestors[k][b])
        {
            a=Ancestors[k][a];
            b=Ancestors[k][b];
        }

    return Ancestors[0][a];
}

int GetDist (int a, int t)
{
    if (Depth[a]<=Depth[t])
        return 0;

    int ret=0, k, log;
    for (log=0; (1 << log)<Depth[a]; ++log);

    for (k=log; k>=0; k--)
        if (UpMost[k][a] && Depth[UpMost[k][a]]>Depth[t])
        {
            a=UpMost[k][a];
            ret+=1 << k;
        }
    if (Depth[a]>Depth[t])
        ret++;

    return ret;
}

void Solve ()
{
    Depth[0]=0;
    for (f >> T; T>=1; T--)
    {
        int a, b, c;
        f >> a >> b;
        a=WComponent[a];
        b=WComponent[b];
        c=LCA(a, b);
        g << GetDist(a, c) << '\n';
    }
}

int main ()
{
    Read();
    CTC();
    BuildAncestors();
    Solve();

    f.close();
    g.close();

    return 0;
}