Cod sursa(job #996345)

Utilizator raulstoinStoin Raul raulstoin Data 11 septembrie 2013 17:47:27
Problema Obiective Scor 5
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.75 kb
//LCA O(N)

#include<fstream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<stack>

#define NMAX 32005
#define VEC(G) G[nod][i]

using namespace std;

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

int m,t;
short n,CTC[NMAX],nr,timp[NMAX],low[NMAX],TT[NMAX],level[NMAX],nivel[NMAX];
vector<short> G[NMAX],GT[NMAX];
stack<short> S;
bool use[NMAX];

void read()
{
	fin>>n>>m;
	for(short x,y;m;m--)
	{
		fin>>x>>y;
		G[x].push_back(y);
		GT[y].push_back(x);
	}
	fin>>t;
}

void PM(short nod)
{
	use[nod]=1;
	for(size_t i=0;i<G[nod].size();i++)
		if(!use[VEC(G)])
			PM(VEC(G));
	S.push(nod);
}

void Kosaraju(short nod)
{
	use[nod]=1;
	CTC[nod]=nr;
	for(size_t i=0;i<GT[nod].size();i++)
		if(!use[VEC(GT)])
			Kosaraju(VEC(GT));
}

void edges_CTC()
{
	for(int i=1;i<=n;i++)
		GT[i].clear();
	for(int nod=1;nod<=n;nod++)
		for(size_t i=0;i<G[nod].size();i++)
			if(CTC[nod]!=CTC[VEC(G)])
				GT[CTC[nod]].push_back(CTC[VEC(G)]);
	n=nr;
}

void topo(short nod)
{
	use[nod]=1;
	for(size_t i=0;i<GT[nod].size();i++)
		if(!use[VEC(GT)])
			topo(VEC(GT));
	timp[nod]=++timp[0];
}

bool cmp(const short a,const short b)
{
	return timp[a]>timp[b];
}

void forward(short nod,short niv)
{
	use[nod]=1;
	nivel[nod]=niv;
	for(size_t i=0;i<GT[nod].size();i++)
	{
		low[VEC(GT)]=nod;
		level[VEC(GT)]=niv;
		if(!use[VEC(GT)])
		{
			TT[VEC(GT)]=nod;
			forward(VEC(GT),niv+1);
		}
	}
}

void lowest(short nod)
{
	use[nod]=1;
	for(size_t i=0;i<GT[nod].size();i++)
		if(!use[VEC(GT)])
			if(level[VEC(GT)]<level[nod])
			{
				level[VEC(GT)]=level[nod];
				low[VEC(GT)]=low[nod];
			}
}

void tree()
{
	for(int i=1;i<=n;i++)
		GT[i].clear();
	for(int i=2;i<=n;i++)
		GT[i].push_back(low[i]);
}

int LCA(short x,short y)
{
	while(x!=y)
	{
		if(nivel[x]>nivel[y])
			x=TT[x];
		if(nivel[x]<nivel[y])
			y=TT[y];
	}
	return x;
}

int main()
{
	read();
	for(int i=1;i<=n;i++) //Plus-Minus
		if(!use[i])
			PM(i);
	
	memset(use,0,sizeof use); //Kosaraju
	for(;!S.empty();S.pop())
		if(!use[S.top()])
		{
			++nr;
			Kosaraju(S.top());
		}
	
	edges_CTC(); //Graful CTC
	
	memset(use,0,sizeof use); //Sortarea listelor
	topo(1); 
	memset(use,0,sizeof use);
	for(int i=1;i<=n;i++)
		sort(GT[i].begin(),GT[i].end(),cmp);
	
	memset(use,0,sizeof use); //Nivelul minim
	level[1]=low[1]=1;
	forward(1,1);
	memset(use,0,sizeof use);
	lowest(1);
	
	tree(); //Arborele low
	
	for(short x,y,L,sol;t;t--)
	{
		fin>>x>>y;
		x=CTC[x];
		y=CTC[y];
		L=LCA(x,y);
		if(x==y || L==x) // x e stramos a lui y
		{
			fout<<"0\n";
			continue;
		}
		sol=0;
		while(nivel[x]>nivel[L])
		{
			x=low[x];
			sol++;
		}
		fout<<sol<<'\n';
	}
	return 0;
}