Cod sursa(job #1882273)

Utilizator RazvanR104Razvan-Andrei Ciocoiu RazvanR104 Data 17 februarie 2017 03:05:03
Problema Obiective Scor 5
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.65 kb
#include <bits/stdc++.h>

using namespace std;

const int NMAX = 32010, LOG2NMAX = 18;

int N, M, T;
int dfn[NMAX], lowLink[NMAX];
int level[NMAX], where[NMAX];
int _level[NMAX];
int RMQ[LOG2NMAX][2 * NMAX], first[NMAX];
int which[NMAX], vertexOrder[NMAX];
int MSB[NMAX];
int ancestor[LOG2NMAX][NMAX];
bool inStack[NMAX];
vector<int> G[NMAX], GT[NMAX];
vector<vector<int>> scc;

struct Compare {
	bool operator()(const int &lhs, const int &rhs) const {
		return vertexOrder[lhs] < vertexOrder[rhs];
	}
};

stack<int> vertex;
void cacheComponent(int x) {
	int nowX;
	int pos = scc.size();
	vector<int> currScc;
	do {
		nowX = vertex.top();
		vertex.pop();
		inStack[nowX] = 0;
		currScc.push_back(nowX);
		which[nowX] = pos;
	} while (nowX != x);
	scc.push_back(currScc);
}

int currTime;
void tarjanDFS(int node) {
	dfn[node] = lowLink[node] = ++currTime;
	vertex.push(node);
	inStack[node] = 1;
	for (const int &it: G[node]) {
		if (!dfn[it]) {
			tarjanDFS(it);
			lowLink[node] = min(lowLink[node], lowLink[it]);
		} else if (inStack[it]) {
			lowLink[node] = min(lowLink[node], dfn[it]);
		}
	}
	if (lowLink[node] == dfn[node])
		cacheComponent(node);
}

vector<int> GS[NMAX], GST[NMAX];
int degree[NMAX];
void buildSccGraph() {
	for (int i = 1; i <= N; ++i)
		for (const int &it: G[i])
			if (which[i] != which[it]) {
				GS[which[i]].push_back(which[it]);
				++degree[which[it]];
			}
}

void DFS(int node, int currLevel, int father) {
	level[node] = currLevel;
	lowLink[node] = currLevel;
	where[node] = node;
	RMQ[0][++RMQ[0][0]] = node;
	first[node] = RMQ[0][0];
	if (father != -1) {
		lowLink[node] = level[father];
		where[node] = father;
	}
	for (const int &it: GS[node]) {
		if (level[it] != -1)
			continue;
		DFS(it, currLevel + 1, node);
		if (lowLink[node] > lowLink[it]) {
			lowLink[node] = lowLink[it];
			where[node] = where[it];
		}
		RMQ[0][++RMQ[0][0]] = node;
	}
	for (const int &it: GST[node]) {
		if (lowLink[node] > level[it]) {
			lowLink[node] = level[it];
			where[node] = it;
		}
	}
}

void computeRMQ() {
	for (int i = 1; (1 << i) <= RMQ[0][0]; ++i)
		for (int j = 1; j + (1 << i) - 1 <= RMQ[0][0]; ++j)
			RMQ[i][j] = level[RMQ[i - 1][j]] < level[RMQ[i - 1][j + (1 << (i - 1))]] ? RMQ[i - 1][j] : RMQ[i - 1][j + (1 << (i - 1))];
}

int computeLCA(int x, int y) {
	if (first[x] > first[y])
		swap(x, y);
	int lgDist = MSB[first[y] - first[x] + 1];
	if (level[RMQ[lgDist][first[x]]] < level[RMQ[lgDist][first[y] - (1 << lgDist) + 1]])
		return RMQ[lgDist][first[x]];
	return RMQ[lgDist][first[y] - (1 << lgDist) + 1];
}

void levelDFS(int node, int currLevel) {
	_level[node] = currLevel;
	for (const int &it: GT[node])
		levelDFS(it, currLevel + 1);
}

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

	int i, j;

	scanf("%d %d", &N, &M);
	while (M--) {
		int x, y;
		scanf("%d %d", &x, &y);
		G[x].push_back(y);
	}

	for (i = 1; i <= N; ++i)
		if (!dfn[i])
			tarjanDFS(i);
	buildSccGraph();

	int pos = 0;
	queue<int> Q;
	int root = -1;
	for (i = 0; i < int(scc.size()); ++i)
		if (degree[i] == 0) {
			root = i;
			Q.push(i);
			vertexOrder[i] = pos++;
			break;
		}

	while (!Q.empty()) {
		int now = Q.front();
		Q.pop();
		for (const int &it: GS[now]) {
			--degree[it];
			if (degree[it] == 0) {
				Q.push(it);
				vertexOrder[it] = pos++;
			}
		}
	}

	for (i = 0; i < int(scc.size()); ++i) {
		sort(GS[i].begin(), GS[i].end(), Compare());
		GS[i].erase(unique(GS[i].begin(), GS[i].end()), GS[i].end());
		for (const int &it: GS[i])
			GST[it].push_back(i);
	}

	memset(lowLink, 0, sizeof lowLink);
	memset(level, -1, sizeof level);
	DFS(root, 0, -1);
	computeRMQ();

	for (i = 2; i <= RMQ[0][0]; ++i)
		if ((i & (i - 1)) == 0)
			MSB[i] = MSB[i - 1] + 1;
		else
			MSB[i] = MSB[i - 1];

	memset(ancestor, -1, sizeof ancestor);
	for (i = 0; i < int(scc.size()); ++i) {
		if (where[i] == i)
			continue;
		ancestor[0][i] = where[i];
		GT[where[i]].push_back(i);
	}

	for (i = 1; (1 << i) < int(scc.size()); ++i)
		for (j = 0; j < int(scc.size()); ++j)
			ancestor[i][j] = ancestor[i - 1][ancestor[i - 1][j]];
	levelDFS(root, 0);

	scanf("%d", &T);
	while (T--) {
		int x, y;
		scanf("%d %d", &x, &y);
		x = which[x];
		y = which[y];
		int nodeX = x;
		int LCA = computeLCA(x, y);
		for (i = LOG2NMAX - 1; i >= 0; --i)
			if (ancestor[i][nodeX] != -1 && level[ancestor[i][nodeX]] > level[LCA])
				nodeX = ancestor[i][nodeX];
		if (nodeX != root && nodeX != LCA)
			nodeX = ancestor[0][nodeX];
		cout << _level[x] - _level[nodeX] << '\n';
	}

	return 0;
}