Cod sursa(job #67565)

Utilizator wefgefAndrei Grigorean wefgef Data 25 iunie 2007 11:48:23
Problema Obiective Scor 100
Compilator cpp Status done
Runda preONI 2007, Runda Finala, Clasele 11-12 Marime 5.13 kb
//bah buru ai dat si tu un tractor, sa mor io... da e marfa ideea ;)
//sigur busesc problema, ca nah.. prea multe linii :P

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

#define sz size()
#define pb push_back

#define inf 1000000000
#define Nmax 32005

int n, m;
vector<int> vec[Nmax], vec2[Nmax];
vector<int> vc[Nmax], vc2[Nmax];

char viz[Nmax];
int list[Nmax], nlist;
int comp[Nmax], nrc;

int place[Nmax];
int level[Nmax];
int lim = 15;
int c[Nmax][16];

int start[Nmax];
int v[200000], nrv;
int seg[200000];

void readdata()
{
    freopen("obiective.in", "r", stdin);
    freopen("obiective.out", "w", stdout);
    
    int i, a, b;
    
    scanf("%d %d", &n, &m);
    for (i = 1; i <= m; ++i)
    {
        scanf("%d %d", &a, &b);
        vec[a].pb(b);
        vec2[b].pb(a);
    }
}

void df1(int k)
{
    int i, nod;
    
    viz[k] = 1;
    for (i = 0; i < vec[k].sz; ++i)
    {
        nod = vec[k][i];
        if (!viz[nod]) df1(nod);
    }
    list[++nlist] = k;
}

void df2(int k)
{
    int i, nod;
    
    viz[k] = 1;
    comp[k] = nrc;
    for (i = 0; i < vec2[k].sz; ++i)
    {
        nod = vec2[k][i];
        if (!viz[nod]) df2(nod);
    }
}

void df3(int k)
{
    int i, nod;
    
    viz[k] = 1;
    for (i = 0; i < vc[k].sz; ++i)
    {
        nod = vc[k][i];
        if (!viz[nod]) df3(nod);
    }
    list[++nlist] = k;
}

inline int cmp(int a, int b)
{ return place[a] < place[b]; }

void df4(int k)
{
    int i, nod, j;
    
    viz[k] = 1;
    v[++nrv] = k;
    start[k] = nrv;
    for (i = 0; i < vc[k].sz; ++i)
    {
        nod = vc[k][i];
        if (!viz[nod])
        {
            level[nod] = level[k]+1;
            df4(nod);
            v[++nrv] = k;
        }
    }
}

void build(int poz, int st, int dr)
{
    if (st == dr)
    {
        seg[poz] = v[st];
        return;
    }
    
    int m = (st+dr)/2, p1 = poz*2, p2 = poz*2+1;
    
    build(p1, st, m);
    build(p2, m+1, dr);
    
    if (level[ seg[p1] ] < level[ seg[p2] ]) seg[poz] = seg[p1];
    else seg[poz] = seg[p2];
}

int interog(int poz, int st, int dr, int a, int b)
{
    if (a <= st && dr <= b) return seg[poz];
    
    int m = (st+dr)/2, p1 = poz*2, p2 = poz*2+1, best = 0, val;
    
    if (a <= m) best = interog(p1, st, m, a, b);
    if (b > m)
    {   
        val = interog(p2, m+1, dr, a, b);
        if (level[val] < level[best]) best = val;
    }
    return best;
}

void solve()
{
    int i, j, nod, nod2;
    
    //afla componentele tare conexe
    for (i = 1; i <= n; ++i)
        if (!viz[i]) df1(i);
        
    memset(viz, 0, sizeof(viz));
    for (i = nlist; i; --i)
        if (!viz[ list[i] ])
        {
            ++nrc;
            df2(list[i]);
        }
           
    //determina graful comprimat    
    for (i = 1; i <= n; ++i)
    for (j = 0; j < vec[i].sz; ++j)
    if (comp[i] != comp[ vec[i][j] ])
        vc[ comp[i] ].pb( comp[ vec[i][j] ] );
         
    for (i = 1; i <= nrc; ++i)
    {
        sort(vc[i].begin(), vc[i].end());
        vc[i].resize( unique(vc[i].begin(), vc[i].end()) - vc[i].begin());
    }
             
    //sorteaza lexicografic noul graf
    memset(viz, 0, sizeof(viz));
    nlist = 0;
    for (i = 1; i <= nrc; ++i)
        if (!viz[i]) df3(i);

    //LCA stuff        
    for (i = 1; i <= nrc; ++i)
        place[ list[i] ] = i;
        
    for (i = 1; i <= nrc; ++i)
        sort(vc[i].rbegin(), vc[i].rend(), cmp);
    for (i = 1; i <= nrc; ++i)
    for (j = 0; j < vc[i].sz; ++j)
    {
        nod = vc[i][j];
        vc2[nod].pb(i);
    }
    
    memset(viz, 0, sizeof(viz));
    level[0] = inf;
    df4(list[nrc]);    
    build(1, 1, nrv);   
    
    //construieste matrice
    for (i = 1; i <= nrc; ++i)
    {
        nod = list[i];
        c[nod][0] = nod;
        for (j = 0; j < vc[nod].sz; ++j)
        {
            nod2 = vc[nod][j];
            if (level[ c[nod2][0] ] < level[ c[nod][0] ])
                c[nod][0] = c[nod2][0];
        }
        for (j = 0; j < vc2[nod].sz; ++j)
        {
            nod2 = vc2[nod][j];
            if (level[nod2] < level[ c[nod][0] ])
                c[nod][0] = nod2;
        }
    }
    
    for (j = 1; j <= lim; ++j)
    for (i = 1; i <= nrc; ++i)
        c[i][j] = c[ c[i][j-1] ][ j-1 ];

}

int solution(int a, int lev)
{
    int ret = 0, i, j;
    
    for (j = lim; j >= 0; --j)
        if (level[ c[a][j] ] > lev)
        {
            a = c[a][j];
            ret += (1 << j);
        }
    if (level[a] > lev) ++ret;
    return ret;
}

void writedata()
{
    int t, a, b, val;
    int v1, v2;
    
    for (scanf("%d", &t); t; --t)
    {
        scanf("%d %d", &a, &b);
        a = comp[a], b = comp[b];        
            
        v1 = start[a], v2 = start[b];
        if (v1 > v2) v1 ^= v2 ^= v1 ^= v2;
             
        val = interog(1, 1, nrv, v1, v2);
        printf("%d\n", solution(a, level[val]));
    }
}

int main()
{
    readdata();
    solve();
    writedata();
    return 0;
}