Cod sursa(job #660646)

Utilizator mlupseLupse-Turpan Mircea mlupse Data 13 ianuarie 2012 11:59:59
Problema Obiective Scor 5
Compilator cpp Status done
Runda Arhiva de probleme Marime 5.68 kb
#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>

using namespace std;

#define CLEAR(x) memset(x, 0, sizeof(x))
#define NMax 32768

int N, M, uz[NMax], timp[NMax], t, ctc, comp[NMax], rad;
int up[16][NMax], nivel[NMax], lg[20], bst;
int get_high[16][NMax], highest[NMax], dep[NMax], t_in[NMax], t_out[NMax];
vector<int> G[NMax], GT[NMax];

int cmp_nodes(const int& a, const int& b)//Functia pentru sortarea listelor de adiacenta in functie de sortarea topologica
{ return t_out[a] > t_out[b]; }	 

void df1(int nod)// Primul DFS (Kosaraju) pentru determinarea CTC
{
	int i, sz, x;

	uz[nod] = 1;
	for (sz = G[nod].size(), i = 0; i < sz; ++i)
		if (!uz[x = G[nod][i]])
			df1(x);
	timp[++t] = nod;
}

void df2(int nod)// Al doilea DFS (Kosaraju) pentru determinarea CTC
{
	int i, size, x;

	uz[nod] = 1; comp[nod] = ctc;
	for (size = GT[nod].size(), i = 0; i < size; ++i)
		if (!uz[x = GT[nod][i]])
			df2(x);
}

int det_root(void)//Determinarea radacinii lui G* (nodul cu gradul de intrare 0)
{
	int i, j, sz;
	
	CLEAR(uz);
	for (i = 1; i <= N; ++i)
		for (sz = GT[i].size(), j = 0; j < sz; ++j)
			uz[GT[i][j]] = 1;
	for (i = 1; i <= N; ++i)
		if (!uz[i])
			return i;				
	return -1; // should never arrive here
}

void df_time(int nod)//Sortarea Topologica a lui G*
{
    int i, sz, x;

    uz[nod] = 1;
    for (sz = GT[nod].size(), i = 0; i < sz; ++i)
        if (!uz[x = GT[nod][i]])
            df_time(x);
    t_out[nod] = (++t);
}

void df3(int nod)//Se construieste vectorul de nivel si vectorul de tati(puteri a lui 2) pentru fiecare nod
{
	int i, sz, x;
	
	uz[nod] = 1;
	for (i = 0; ; ++i)
	{
		if (!up[i][ up[i][nod] ]) break;
		up[i+1][nod] = up[i][ up[i][nod] ];
	}
	
	for (sz = GT[nod].size(), i = 0; i < sz; ++i)
		if (!uz[x = GT[nod][i]])
		{
			up[0][x] = nod;
			nivel[x] = nivel[nod] + 1;
			df3(x);
		}
}

int LCA(int x, int y)
{
	for (; nivel[x] > nivel[y]; x = up[ lg[nivel[x]-nivel[y]] ][x]);
	for (; nivel[y] > nivel[x]; y = up[ lg[nivel[y]-nivel[x]] ][y]);
	if (x == y) return x;

	int log;
	for (log = lg[nivel[x]]; log >= 0; --log)
		if (up[log][x] != up[log][y])
			x = up[log][x], 
			y = up[log][y];
	if (x != y) x = up[0][x];
	return x;
}

void df4(int nod)
{
	int i, sz, x;

	uz[nod] = 1;
	for (sz = GT[nod].size(), i = 0; i < sz; ++i)
		if (!uz[x = GT[nod][i]])
		{
			df4(x);
			if (nivel[ highest[x] ] < nivel[ highest[nod] ])
				highest[nod] = highest[x];
		}
}

void df5(int nod)
{
	int i, sz, x;
	
	for (i = 0; ; ++i)
	{
		if (!get_high[i][ get_high[i][nod] ]) break;
		get_high[i+1][nod] = get_high[i][ get_high[i][nod] ];
	}
	
	uz[nod] = 1;
	for (sz = G[nod].size(), i = 0; i < sz; ++i)
		if (!uz[x = G[nod][i]])
		{
			get_high[0][x] = nod;
			dep[x] = dep[nod] + 1;
			df5(x);
		}
}

void df6(int nod)
{
	int i, sz, x;

	uz[nod] = 1; t_in[nod] = (++t);
	for (sz = GT[nod].size(), i = 0; i < sz; ++i)
		if (!uz[x = GT[nod][i]])
			df6(x);
	t_out[nod] = (++t);
}

int stramos(int x, int y)
{ return t_in[x] <= t_in[y] && t_out[y] <= t_out[x]; }

int main(void)
{
	int T, i, j, k, sz, log;
	
	freopen("obiective.in", "r", stdin);
	freopen("obiective.out", "w", stdout);
//Citire
	scanf("%d %d", &N, &M);
	for (; M; --M)
	{
		scanf("%d %d", &i, &j);
		G[i].push_back(j);//Construire Graf
		GT[j].push_back(i);//Construire Graf Transpus (pentru Kosaraju)
	}
//Primul DFS pentru CTC (Kosaraju) Se construieste vectorul de timpi timp[i] pentru DFS 2
	
	for (i = 1; i <= N; ++i)
		if (!uz[i])
			df1(i);	
//Al doilea DFS pentru CTC (Kosaraju) Se stabileste pentru fiecare nod carei componente conexe ii apartine comp[nod]
		CLEAR(uz);// Componentele conexe sunt in ordinea sortarii topologice datorita DFS 1
	for (i = N; i; --i)
		if (!uz[j = timp[i]])
		{
			++ctc;
			df2(j);
		}

	for (i = 1; i <= N; ++i)//Se refoloseste GT pentru a forma graful G* (graful componentelor tare conexe)
		GT[i].clear();
	for (i = 1; i <= N; ++i)
		for (sz = G[i].size(), j = 0; j < sz; ++j)//GT va contine doar muchiile dintre componentele tare conexe
			if (comp[i] != comp[G[i][j]])//Fiecarui nod x din G ii corespunde nodul comp[x] din GT
				GT[comp[i]].push_back( comp[G[i][j]] );//Astfel GT are N=ctc noduri
	N = ctc;                
	//rad = det_root(); //Se afla radacina lui G* (nodul care are gradul de intrare 0)               
	t = 0;
	CLEAR(uz);    
	df_time(timp[N]);//Sortarea Topologica a lui G(G este aciclic) pornind din radacina rad
	for (i = 1; i <= N; ++i)//Se sorteaza listele de adiacenta conform sortarii topologice DF_TIME
		sort(GT[i].begin(), GT[i].end(), cmp_nodes);

	CLEAR(uz);
	df3(rad);//Se construieste vectorul up (tatii puteri ai lui 2) pentru fiecare nod
	for (i = 2; i< 17; ++i)
		lg[i] = lg[i/2]+1;

	for (i = 1; i <= N; ++i)//Se initializeaza vectorul highest cu vectorul de tati
		highest[i] = up[0][i];
	
	for (i = 1; i <= N; ++i)
		for (sz = GT[i].size(), j = 0; j < sz; ++j)
    		if (up[0][ GT[i][j] ] != i)
			{
				if (nivel[i] < nivel[ highest[ GT[i][j] ] ])
					highest[ GT[i][j] ] = i;
			}	
	CLEAR(uz);
	df4(rad);
	
	for (i = 1; i <= N; ++i)//Refolosesc G pentru a construi arborele final
		G[i].clear();
	for (i = 1; i <= N; ++i)
	{
		if (!highest[i]) continue;
		G[highest[i]].push_back(i);//Vectorul highest este vectorul de tati pentru arbore
	}
	CLEAR(uz);
	df5(rad);
    
	t = 0;
	CLEAR(uz);
	CLEAR(t_out);
	df6(rad);

	for (scanf("%d", &T); T; --T)
	{
		scanf("%d %d", &i, &j);
		i = comp[i]; j = comp[j];
		if (i == j)
		{
			printf("0\n");
			continue;
		}
	
		k = LCA(i, j);
		if (i == k)
		{
			printf("0\n");
			continue;
		}
        j = i;
        for (log = lg[dep[i]]; log >= 0; --log)
        {
            if (!get_high[log][i]) continue;
            if (stramos(get_high[log][i], k)) continue;
            i = get_high[log][i];
        }

		printf("%d\n", dep[j] - dep[i] + 1);
	}
	
	return 0;		
}