Cod sursa(job #1048937)

Utilizator florin.elfusFlorin Elfus florin.elfus Data 6 decembrie 2013 17:30:55
Problema Obiective Scor 15
Compilator cpp Status done
Runda Lista lui wefgef Marime 4.53 kb
#include <stdio.h>
#include <vector>
#include <string.h>
#include <algorithm>
#include <iostream>

using namespace std;

vector <int> ini[32100], GTini[32100], G[32100];
bool vis[32100];
int N, M, cnt, st[32100];
int iniToG[32100];

void dfs(int nod) {
    vis[nod] = 1;
    vector <int> :: iterator it;
    for (it = GTini[nod].begin(); it != GTini[nod].end(); ++it)
        if (!vis[*it])
            dfs(*it);
    st[++st[0]] = nod;
}

void dfs2(int nod) {
    vis[nod] = 1;
    iniToG[nod] = cnt;
    vector <int> :: iterator it;
    for (it = ini[nod].begin(); it != ini[nod].end(); ++it)
        if (!vis[*it])
            dfs2(*it);
        else
            if (iniToG[nod] != iniToG[*it])
                G[iniToG[nod]].push_back(iniToG[*it]);
}

void buildDAG() {
    for (int i = 1; i <= N; ++i)
        if (!vis[i])
            dfs(i);
    memset(vis, 0, sizeof(vis));
    for (int i = st[0]; i >= 1; --i)
        if (!vis[st[i]]) {
            ++cnt;
            dfs2(st[i]);
        }
    N = cnt;
    for (int i = 1; i <= N; ++i) {
        vector <int> :: iterator it;
        it = unique(G[i].begin(), G[i].end());
        G[i].resize(distance(G[i].begin(), it));
    }
}

int root, deg[32100];

void findRoot() {
    for (int i = 1; i <= N; ++i) {
        vector <int> :: iterator it;
        for (it = G[i].begin(); it != G[i].end(); ++it)
            ++deg[*it];
    }
    for (int i = 1; i <= N; ++i)
        if (deg[i] == 0)
            root = i;
}

vector <int> treeEdge[32100], forwardEdge[32100];
int Lev[2 * 32100], First[32100], nodeLev[32100], Lg[66000];
int rmq[16][65000];

void dfs3(int nod, int level) {
    Lev[++cnt] = level;
    First[nod] = cnt;
    nodeLev[nod] = level;
    vector <int> :: iterator it;
    for (it = G[nod].begin(); it != G[nod].end(); ++it)
        if (!First[*it]) {
            dfs3(*it, level + 1);
            treeEdge[nod].push_back(*it);
            Lev[++cnt] = level;
        } else
            forwardEdge[*it].push_back(nod);
}

void RMQ() {
    for (int i = 0; i <= cnt; ++i)
        rmq[0][i] = Lev[i];
    for (int i = 1; (1 << i) <= cnt; ++i)
        for (int j = 1; j + (1 << i) - 1 <= cnt; ++j)
            rmq[i][j] = min(rmq[i - 1][j], rmq[i - 1][j + (1 << (i - 1))]);
    for (int i = 2; i < 66000; ++i)
        Lg[i] = Lg[i / 2] + 1;
}

int LCA(int xx, int yy) {
    xx = First[xx];
    yy = First[yy];
    if (xx > yy)
        swap(xx, yy);
    int len = Lg[yy - xx + 1];
    return min(rmq[len][xx], rmq[len][yy - (1 << len) + 1]);
}

int up[16][65000];

void dfs4(int nod, int father) {
    vector <int> :: iterator it;
    for (it = G[nod].begin(); it != G[nod].end(); ++it)
        dfs4(*it, nod);
    if (father == -1)
        return ;
    int bestUp = father, bestLev = nodeLev[father];
    for (it = treeEdge[nod].begin(); it != treeEdge[nod].end(); ++it)
        if (nodeLev[up[0][*it]] < bestLev) {
            bestUp = up[0][*it];
            bestLev = nodeLev[up[0][*it]];
        }
    for (it = forwardEdge[nod].begin(); it != forwardEdge[nod].end(); ++it)
        if (nodeLev[*it] < bestLev) {
            bestUp = *it;
            bestLev = nodeLev[*it];
        }
    up[0][nod] = bestUp;
}

void levelAscensor() {
    for (int i = 1; (1 << i) <= N; ++i)
        for (int j = 1; j <= N; ++j)
            up[i][j] = up[i - 1][up[i - 1][j]];
}

bool can(int times, int nod, int wantedH) {
    for (int b = 0; (1 << b) <= times; ++b)
        if (times & (1 << b))
            nod = up[b][nod];
    return nodeLev[nod] <= wantedH;
}

int solveQuery(int xx, int yy) {
    xx = iniToG[xx];
    yy = iniToG[yy];
    int expected = LCA(xx, yy), res = 0;
    int st = 1, dr = nodeLev[xx] - expected, ret = 0;
    while (st <= dr) {
        int med = (st + dr) / 2;
        if (can(med, xx, expected))
            dr = med - 1, ret = med;
        else
            st = med + 1;
    }
    return ret;
}

int main() {
    freopen("obiective.in", "r", stdin);
    freopen("obiective.out", "w", stdout);

    scanf("%d%d", &N, &M);
    for (int i = 1; i <= M; ++i) {
        int xx, yy;
        scanf("%d%d", &xx, &yy);
        ini[xx].push_back(yy);
        GTini[yy].push_back(xx);
    }

    buildDAG();
    findRoot();
    cnt = 0;
    dfs3(root, 1);
    RMQ();
    dfs4(root, -1);
    levelAscensor();

    int Q;
    scanf("%d", &Q);
    while (Q--) {
        int xx, yy;
        scanf("%d%d", &xx, &yy);
        printf("%d\n", solveQuery(xx, yy));
    }

    return 0;
}