Cod sursa(job #1384359)

Utilizator vladrochianVlad Rochian vladrochian Data 11 martie 2015 01:33:17
Problema Obiective Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.77 kb
#include <fstream>
#include <vector>
#include <stack>
#include <set>
#include <cstring>
using namespace std;

const int kMaxN = 32005, kMaxLog = 16;

ifstream fin("obiective.in");
ofstream fout("obiective.out");

int nodes;
vector<int> graph[kMaxN], transpose_graph[kMaxN];
stack<int> ksr_st;
bool use[kMaxN];
int ctc_nr, ctc[kMaxN];
set<int> ctc_graph[kMaxN];
int ancestor[kMaxLog][kMaxN];
int lg2[kMaxN << 1];
int rmq[kMaxLog][kMaxN << 1], euler_crt, first[kMaxN];


void ReadGraph() {
	int edges;
	fin >> nodes >> edges;
	while (edges--) {
		int x, y;
		fin >> x >> y;
		graph[x].push_back(y);
		transpose_graph[y].push_back(x);
	}
}

void KosarajuNormalDFS(int node) {
	use[node] = true;
	for (int i : graph[node])
		if (!use[i])
			KosarajuNormalDFS(i);
	ksr_st.push(node);
}

void KosarajuTransposeDFS(int node) {
	ctc[node] = ctc_nr;
	for (int i : transpose_graph[node])
		if (!ctc[i])
			KosarajuTransposeDFS(i);
}

void Kosaraju() {
	for (int i = 1; i <= nodes; ++i)
		if (!use[i])
			KosarajuNormalDFS(i);
	while (!ksr_st.empty()) {
		if (!ctc[ksr_st.top()]) {
			++ctc_nr;
			KosarajuTransposeDFS(ksr_st.top());
		}
		ksr_st.pop();
	}
}

void CTCDFS(int node) {
	use[node] = true;
	rmq[0][++euler_crt] = node;
	first[node] = euler_crt;
	for (int i : ctc_graph[node])
		if (!use[i]) {
			CTCDFS(i);
			rmq[0][++euler_crt] = node;
			ancestor[0][node] = min(ancestor[0][node], ancestor[0][i]);
		}
}

void BuildTree() {
	for (int i = 1; i <= ctc_nr; ++i)
		ancestor[0][i] = i;
	for (int i = 1; i <= nodes; ++i) {
		int x = ctc[i];
		for (int j : graph[i]) {
			int y = ctc[j];
			if (x != y) {
				ctc_graph[x].insert(y);
				ancestor[0][y] = min(ancestor[0][y], x);
			}
		}
	}
	memset(use, 0, sizeof use);
	CTCDFS(1);
	for (int i = 2; i < (kMaxN << 1); ++i)
		lg2[i] = lg2[i >> 1] + 1;
	for (int i = 1; i <= lg2[ctc_nr]; ++i)
		for (int j = 1; j <= ctc_nr; ++j)
			ancestor[i][j] = ancestor[i - 1][ancestor[i - 1][j]];
	for (int i = 1; i <= lg2[euler_crt]; ++i)
		for (int j = 1; j <= euler_crt - (1 << i) + 1; ++j)
			rmq[i][j] = min(rmq[i - 1][j], rmq[i - 1][j + (1 << (i - 1))]);
}

int LCA(int x, int y) {
	x = first[x];
	y = first[y];
	if (x > y)
		swap(x, y);
	int lg = lg2[y - x];
	return min(rmq[lg][x], rmq[lg][y - (1 << lg) + 1]);
}

void SolveQueries() {
	int q;
	fin >> q;
	while (q--) {
		int x, y, lca, u, ans = 1;
		fin >> x >> y;
		x = ctc[x];
		y = ctc[y];
		lca = LCA(x, y);
		if (x == lca) {
			fout << "0\n";
			continue;
		}
		u = x;
		for (int i = lg2[ctc_nr]; i >= 0; --i)
			if (ancestor[i][u] > lca) {
				u = ancestor[i][u];
				ans += 1 << i;
			}
		fout << ans << "\n";
	}
}

int main() {
	ReadGraph();
	Kosaraju();
	BuildTree();
	SolveQueries();
	return 0;
}