Cod sursa(job #690432)

Utilizator okros_alexandruOkros Alexandru okros_alexandru Data 25 februarie 2012 16:57:37
Problema Obiective Scor 5
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.7 kb
#include <fstream>
#include <vector>
#include <algorithm>
#define NMAx 32768
#define LMAx 16
#define pb push_back
using namespace std;

vector <int> G[NMAx],GT[NMAx];
int color,viz[NMAx],COMP[NMAx],GR_INT[NMAx];
int n,Teste,nr,CTC,RAD,t_OUT[NMAx],t_IN[NMAx];
int T[LMAx][NMAx],NIVEL[NMAx],LOG2[NMAx],Highest[NMAx];
int GET_HIGH[LMAx][NMAx],DEPTH[NMAx];

bool stramos(int X,int Y) {
	return t_IN[X]<t_IN[Y]&&t_OUT[Y]<t_OUT[X];
}
int LCA(int X,int Y) {
	
	while(NIVEL[X]>NIVEL[Y])
		X=T[ LOG2[NIVEL[X] - NIVEL[Y]] ][X];
	while(NIVEL[Y]>NIVEL[X])
		Y=T[ LOG2[NIVEL[Y] - NIVEL[X]] ][Y];
	
	if(X==Y)
		return X;
	
	for(int LG=LOG2[NIVEL[X]];LG>=0;LG--)
		if(T[LG][X]!=T[LG][Y]) {
			X=T[LG][X];
			Y=T[LG][Y];
			}
	if(X!=Y)
		X=T[0][X];
	
	return X;
	
}
void sortare_topologica3(int nod) {
	
	viz[nod]=color;
	t_IN[nod]=++nr;
	for(int i=0;i<GT[nod].size();i++)
		if(viz[GT[nod][i]]!=color)
			sortare_topologica3(GT[nod][i]);
	
	t_OUT[nod]=++nr;
	
}
void DFS_GH(int nod) {
	
	int i,vecin;
	
	viz[nod]=color;
	for(i=0;GET_HIGH[i][ GET_HIGH[i][nod] ];i++)
		GET_HIGH[i+1][nod]=GET_HIGH[i][ GET_HIGH[i][nod] ];
	
	for(i=0;i<G[nod].size();i++)
		if(viz[vecin = G[nod][i]]!=color) {
			GET_HIGH[0][vecin]=nod;
			DEPTH[vecin]=DEPTH[nod]+1;
			DFS_GH(vecin);
			}
	
}
void DFS_H(int nod) {
	
	int vecin;
	
	viz[nod]=color;
	for(int i=0;i<GT[nod].size();i++)
		if(viz[vecin = GT[nod][i]]!=color) {
			DFS_H(vecin);
			
			if(NIVEL[Highest[vecin]]<NIVEL[Highest[nod]])
				Highest[nod]=Highest[vecin];
			}
	
}
void DFS_T(int nod) {
	
	int i,vecin;
	
	viz[nod]=color;
	for(i=0;T[i][ T[i][nod] ];i++)
		T[i+1][nod]=T[i][ T[i][nod] ];
	
	for(i=0;i<GT[nod].size();i++)
		if(viz[vecin = GT[nod][i]]!=color) {
			T[0][vecin]=nod;
			NIVEL[vecin]=NIVEL[nod]+1;
			DFS_T(vecin);
			}

}
bool cmp(int a,int b) {
	return t_OUT[a]>t_OUT[b];
}
void sortare_topologica2(int nod) {
	
	viz[nod]=color;
	for(int i=0;i<GT[nod].size();i++)
		if(viz[GT[nod][i]]!=color)
			sortare_topologica2(GT[nod][i]);
	
	t_OUT[nod]=++nr;
	
}
void DFS_CTC(int nod) {
	
	COMP[nod]=CTC;
	viz[nod]=color;
	for(int i=0;i<GT[nod].size();i++)
		if(viz[GT[nod][i]]!=color)
			DFS_CTC(GT[nod][i]);
	
}
void sortare_topologica(int nod) {
	
	viz[nod]=color;
	for(int i=0;i<G[nod].size();i++)
		if(viz[G[nod][i]]!=color)
			sortare_topologica(G[nod][i]);
		
	t_OUT[nr--]=nod;
		
}
int main() {
	
	int i,j,x,y,m,nod,vecin,A,B,C,LG;
	ifstream in("obiective.in");
	ofstream out("obiective.out");
	in>>n>>m;
	
	// citire si creare G si GT
	for(i=0;i<m;i++) {
		in>>x>>y;
		G[x].pb(y);
		GT[y].pb(x);
		}
	
	// determinare CTC cu Kosaraju
	for(i=1,color++,nr=n;i<=n;i++)
		if(viz[i]!=color)
			sortare_topologica(i);
	
	for(i=1,color++;i<=n;i++)
		if(viz[t_OUT[i]]!=color) {
			++CTC;
			DFS_CTC(t_OUT[i]);
			}
		
	// creare G* (in GT) cu muchii intre CTC
	for(i=1;i<=n;i++)
		GT[i].clear();
	
	for(i=1;i<=n;i++)
		for(j=0;j<G[i].size();j++)
			if(COMP[i]!=COMP[vecin = G[i][j]]) {
				GT[COMP[i]].pb(COMP[vecin]);
				GR_INT[COMP[vecin]]++;
				}

	n=CTC;

	// Determinare radacina G* (nodul cu grad de intrare 0)
	for(i=1;i<=n&&!RAD;i++)
		if(!GR_INT[i])
			RAD=i;
	
	// Sortare topologica pt G* din radacina
	color++;
	nr=0;
	sortare_topologica2(RAD);
	
	// Se sorteaza listele de adiacenta pt G* conform sortarii topologice
	for(i=1;i<=n;i++)
		sort(GT[i].begin(),GT[i].end(),cmp);
	
	// Se construieste vectorul de tati (puteri alui 2)
	color++;
	DFS_T(RAD);
	
	// Se construieste vectorul LOG2
	for(i=2;i<NMAx;i++)
		LOG2[i]=LOG2[i/2]+1;
	
	// Se construieste Highest[i] cea mai mare inaltime la care poate ajunge nodul i cu cost 1
	for(i=1;i<=n;i++)
		Highest[i]=T[0][i];
	
	for(nod=1;nod<=n;nod++)
		for(j=0;j<GT[nod].size();j++)
			if(T[0][vecin = GT[nod][j]]!=nod)
				if(NIVEL[nod]<NIVEL[Highest[vecin]])
					Highest[vecin]=nod;
	
	color++;
	DFS_H(RAD);
	
	// Se construieste arborul final (in G)
	for(i=1;i<=n;i++)
		G[i].clear();
	
	for(i=1;i<=n;i++)
		if(Highest[i])
			G[Highest[i]].pb(i);
	
	// Se construieste vectorul GET_HIGH ?
	color++;
	DFS_GH(RAD);
	
	// Sortare topologica pt arbore final
	color++;
	nr=0;
	sortare_topologica3(RAD);
	
	// rezolvarea ofertelor
	in>>Teste;
	
	for(i=1;i<=Teste;i++) {
		in>>A>>B;
		
		A=COMP[A];
		B=COMP[B];
		
		if(A==B) {
			out<<"0\n";
			continue;
			}
		
		C=LCA(A,B);
		
		if(C==A) {
			out<<"0\n";
			continue;
			}
		
		B=A;
		for(LG=LOG2[DEPTH[A]];LG>=0;LG--) {
			if(!GET_HIGH[LG][A]) continue;
			if(stramos(GET_HIGH[LG][A],C)) continue;
			A=GET_HIGH[LG][A];
			}
		
		out<<(DEPTH[B]-DEPTH[A])<<'\n';
		}
	
	in.close();
	out.close();
	
	return 0;

}