Cod sursa(job #887078)

Utilizator veleanduAlex Velea veleandu Data 23 februarie 2013 15:20:51
Problema Radiatie Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.54 kb
#include <cstdio>
#include <ctime>
#include <cstdlib>

#include <algorithm>
#include <vector>

using namespace std;

#define max_n 15005
#define max_q 15005
#define max_m 30005

#define fi first
#define se second
#define FORIT( it,v ) for( typeof((v).begin()) it=(v).begin(); it!=(v).end(); ++it )
#define pb push_back

struct muchie {
	int a,b,c;
	muchie(){
		a=b=c=0;
	}
	int other( int nod ){
		return a+b-nod;
	}
	bool operator < ( const muchie b ) const {
		return c < b.c;
	}
} Edge[ max_m ];

vector<muchie> Vertex[ max_n ];
int n,m,q;
pair<int,int> Query[ max_q ];

void read(){

	freopen("radiatie.in","r",stdin);
	freopen("radiatie.out","w",stdout);

	int i;
	scanf("%d %d %d", &n, &m, &q );
	for ( i=1; i<=m; ++i ){
		scanf("%d %d %d", &Edge[ i ].a, &Edge[ i ].b, &Edge[ i ].c );
	}
	for( i=1; i<=q; ++i ){
		scanf("%d %d", &Query[ i ].fi, &Query[ i ].se );
	}
}

bool Viz_m[ max_m ];
int Father[ max_n ];

int get_set( int nod ){
	if( Father[ nod ] != nod ){
		Father[ nod ] = get_set( Father[ nod ] );
	}         
	return Father[ nod ];
}

bool unite( int a, int b ){
 	int ma = get_set( a ), mb = get_set( b );
	if( ma == mb )
		return 0;
	else{
		int x = rand()%2;
		if ( x )
			Father[ ma ] = mb;
		else
			Father[ mb ] = ma;
		return 1;
	}
}

void make_apm(){
	int i;
	sort( Edge+1, Edge+m+1 );
	for( i=1; i<=n; ++i ){
		Father[ i ] = i;
	}
	for( i=1; i<=m; ++i ){
		if ( unite( Edge[ i ].a, Edge[ i ].b ) ){
			Viz_m[ i ] = 1;
		}
	}
	for( i=1; i<=m; ++i ){
		if( Viz_m[ i ] ){
			Vertex[ Edge[ i ].a ].pb( Edge[ i ] );
			Vertex[ Edge[ i ].b ].pb( Edge[ i ] );
		}
	}
}

int First[ max_n ], Level[ max_n ], Parcurgere[ 2*max_n ], p;
pair< int,int > Parent[ max_n ][ 20 ];
int RMQ[ 2*max_n ][ 20 ], Log[ 2*max_n ];
bool Viz[ max_n ];

void euler( int nod, int level ){
	Viz[ nod ] = 1;
	Parcurgere[ ++p ] = level;
	First[ nod ] = p;
	Level[ nod ] = level;
	FORIT( it, Vertex[ nod ] ){
		if( !Viz[ it->other( nod ) ]){
			euler( it->other( nod ), level+1 );
			Parent[ it->other( nod ) ][ 0 ] = make_pair( nod, it->c );
			Parcurgere[ ++p ] = level;
		}
	}
}

void make_rmq(){
	int i,l;
	euler( 1,1 );	
	Log[ 0 ] = Log[ 1 ] = 0;
	for( i=2; i<=p; ++i ){
		Log[ i ] = Log[ i>>1 ] + 1;
	}
	for( i=1; i<=p; ++i ){
		RMQ[ i ][ 0 ] = Parcurgere[ i ];
	}
	for( l=1; (1<<l) <= p; ++l ){
		for( i=1; i-1+(1<<l) <=p; ++i ){
			RMQ[ i ][ l ] = min( RMQ[ i ][ l-1 ], RMQ[ i+(1<<(l-1)) ][ l-1 ] );
		}
	}
	// facem parentii
	int nod,cost;
	for( l=1; (1<<l) <= p; ++l ){
		for( i=1; i<=n; ++i ){
			nod = Parent[ i ][ l-1 ].fi;
			cost = Parent[ i ][ l-1 ].se;
			cost = max( cost, Parent[ nod ][ l-1 ].se );
			Parent[ i ][ l ] = make_pair( Parent[ nod ][ l-1 ].fi, cost );
		}
	}
}

int go_deeper( int nod, int target ){
	int result=0, act=0;
	while( target ){
		if( target & (1<<act) ){
			result = max( result, Parent[ nod ][ act ].se );
			nod = Parent[ nod ][ act ].fi;
			target ^= (1<<act);
		}
		act++;
	}
	return result;
}

void solve(){
	int i,a,b,d,l,target,result;
	for( i=1; i<=q; ++i ){
		a = Query[ i ].fi;
		b = Query[ i ].se;
		// facem rmq
		a = First[ a ];
		b = First[ b ];
		if ( a > b )
			swap( a,b );
		d = b-a+1;
		l = Log[ d ];
		target = min( RMQ[ a ][ l ], RMQ[ b-(1<<l)+1 ][ l ] );
		// stim nivelul LCA-ului

		// pentru a afla rezultatul, trebuie sa parcurgem pana la acel nivel sa vedem ce valori intalnim, si sa o luam pe cea maxima.
		a = Query[ i ].fi;
		b = Query[ i ].se;
		result = go_deeper( a, Level[ a ]-target );
		result = max( result, go_deeper( b, Level[ b ]-target ) );
		printf("%d\n",result);
	}
}

int main(){
	read();
	make_apm();
	make_rmq();
	solve();
	return 0;
}