Cod sursa(job #1766295)

Utilizator depevladVlad Dumitru-Popescu depevlad Data 27 septembrie 2016 20:10:23
Problema Obiective Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.93 kb
#include <bits/stdc++.h>

using namespace std;

const int kMaxN = 35005;
const int kMaxLog = 17;

int n, m, t, nc;
vector <int> graph[kMaxN];

/** Disjoint Forests */

int root[kMaxN];

void startForests() {
    srand(time(nullptr));
    for (int i = 1; i <= nc; i++) {
        root[i] = i;
    }
}

int findRoot(const int x) {
    if (x == root[x]) {
        return x;
    }
    return (root[x] = findRoot(root[x]));
}

bool mergeSets(const int x, const int y) {
    int xr = findRoot(x);
    int yr = findRoot(y);
    if (xr != yr) {
        if (rand() & 1) {
            swap(xr, yr);
        }
        root[xr] = yr;
        return true;
    }
    else {
        return false;
    }
}

/** END Disjoint Forests */

int dfOrder;
int dfn[kMaxN];
int cid[kMaxN];
bool onStack[kMaxN];
stack <int> sccStack;
vector <int> scc[kMaxN];
vector <int> ctree[kMaxN];
vector <int> cback[kMaxN];

/** Strongly Connected Components and Tree */

int findScc(const int u) {
    dfOrder++;
    dfn[u] = dfOrder;
    int minPtr = dfOrder;
    sccStack.push(u);
    onStack[u] = true;
    for (const int v: graph[u]) {
        if (!dfn[v]) {
            minPtr = min(minPtr, findScc(v));
        }
        else if (onStack[v]) {
            minPtr = min(minPtr, dfn[v]);
        }
    }
    if (dfn[u] == minPtr) {
        int v;
        nc++; 
        do {
            v = sccStack.top();
            sccStack.pop();
            cid[v] = nc;
            onStack[v] = false;
            scc[nc].push_back(v);
        } while (v != u);
    }
    return minPtr;
}

void topSort() {
    for (int i = 1; i < nc - i + 1; i++) {
        swap(scc[i], scc[nc - i + 1]);
    }
    for (int i = 1; i <= n; i++) {
        cid[i] = nc - cid[i] + 1;
    }
}

void buildSccTree() {
    topSort();
    startForests();
    for (int i = 1; i <= nc; i++) {
        set <int> cfound;
        for (const int u: scc[i]) {
            for (const int v: graph[u]) {
                if (i != cid[v]) {
                    cfound.insert(cid[v]);
                }
            }
        }
        for (const int u: cfound) {
            if (mergeSets(i, u) == true) {
                ctree[i].push_back(u);
            }
            else {
                cback[u].push_back(i);
            }
        }
    }
}

/** END Strongly Connected Components and Tree */

/** Tree Processing */

int depthCompressed[kMaxN];
int anc[kMaxLog][kMaxN];
int depth[kMaxN];
int up[kMaxN];

void getAncestors() {
    for (int i = 1; i < kMaxLog; i++) {
        for (int j = 1; j <= nc; j++) {
            anc[i][j] = anc[i - 1][anc[i - 1][j]];
        }
    }
}

void getLowpoint(const int u) {
    for (const int v: ctree[u]) {
        depth[v] = depth[u] + 1;
        anc[0][v] = u;
        up[v] = u;
        getLowpoint(v);
        if (depth[up[u]] > depth[up[v]]) {
            up[u] = up[v];
        }
    }
    for (const int v: cback[u]) {
        if (depth[up[u]] > depth[v]) {
            up[u] = v;
        }
    }
}

int getLca(int x, int y) {
    if (depth[x] < depth[y]) {
        swap(x, y);
    }
    int hdif = depth[x] - depth[y];
    for (int i = 0; hdif > 0; i++, hdif >>= 1) {
        if (hdif & 1) {
            y = anc[i][y];
        }
    }
    if (x == y) {
        return x;
    }
    for (int i = kMaxLog - 1; i >= 0; i--) {
        if (anc[i][x] != anc[i][y]) {
            x = anc[i][x];
            y = anc[i][y];
        }
    }
    return anc[0][x];
}

int compressUp(const int x) {
    if (depthCompressed[x] > 0) {
        return depthCompressed[x];
    }
    return compressUp(up[x]) + 1;
}


void getCompressedDepth() {
    depthCompressed[1] = 1;
    for (int i = 2; i <= nc; i++) {
        if (!depthCompressed[i]) {
            depthCompressed[i] = compressUp(i);
        }
    }
}

/** END Tree Processing */

/** Complete Preprocessing */

void processGraph() {
    findScc(1);
    buildSccTree();
}

void processTree() {
    depth[1] = 1;
    up[1] = 1;
    getLowpoint(1);
    getAncestors();
    getCompressedDepth();
}

void fullPreprocess() {
    processGraph();
    processTree();
}

/** END Complete Preprocessing */

/** Helper Functions */

int solveQuery(const int x, const int y) {
    const int u = getLca(cid[x], cid[y]);
    return depthCompressed[cid[x]] - min(depthCompressed[u], depthCompressed[up[u]]) - 1;
}

/** END Helper Functions */

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 u, v;
        scanf("%d %d", &u, &v);
        graph[u].push_back(v);
    }
    fullPreprocess();
    int q;
    for (scanf("%d", &q); q > 0; q--) {
        int u, v;
        scanf("%d %d", &u, &v);
        printf("%d\n", solveQuery(u, v));
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}