Cod sursa(job #789656)

Utilizator vendettaSalajan Razvan vendetta Data 18 septembrie 2012 20:26:16
Problema Radiatie Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 5.09 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <set>
#include <queue>
#include <deque>

using namespace std;

ifstream f("radiatie.in");
ofstream g("radiatie.out");

#define nmax 15005
#define Mmax 30005
#define inf (1<<29)
#define ll long long

int n, m, K, t[nmax];
vector<pair<int,int> > gf[nmax];
pair<int, pair<int,int> > mc[Mmax];
int aint[nmax*4*2], v[2*nmax], P[nmax], nivel[nmax];
bool viz[nmax];
int Max[15][nmax], tata[15][nmax];

void citeste(){

	f >> n >> m >> K;//numarul de noduri; numarul de muchii; numarul de query-uri
    for(int i=1; i<=m; ++i){
        int x, y, c;
        f >> x >> y >> c;
        mc[i] = make_pair( c, make_pair(x,y) );
    }

}

int radacina(int X){

    int i = X;

    for(; t[X]!=0; X=t[X]);

    while(i != X){
        int aux = t[i];
        t[i] = X;
        i = aux;
    }

    return X;

}

void uneste(int X, int Y){

    t[X] = Y;

}

void fa_APM(){

    //fac cu Kruskal

    sort(mc+1, mc+m+1);

    for(int i=1; i<=m; ++i){
        int X = mc[i].second.first;
        int Y = mc[i].second.second;
        int cost = mc[i].first;
        int rad_X = radacina(X);//radacina lui X
        int rad_Y = radacina(Y);
        if (rad_X == rad_Y) continue;//daca sunt deja in arbore nu le mai bag
        gf[X].push_back(make_pair(Y,cost));
        gf[Y].push_back(make_pair(X,cost));
        //cout << X << " " << Y << " " << cost << "\n";
        uneste( rad_X, rad_Y );
    }

}

void initializeaza(int vc, int nod, int cost){

    //initializez Max[i][j] si tata[i][j]

    Max[0][vc] = cost;//muchia maxima de pe drum vc, al 2^0-lea tata va fi cost
    tata[0][vc] = nod;//si tatal al 2^0-lea va fi nod

}

void dfs(int nod, int niv){

    viz[nod] = 1;
    nivel[nod] = niv;
    v[ ++v[0] ] = nod;
    P[nod] = v[0];

    for(int i=0; i<gf[nod].size(); ++i){
        int vc = gf[nod][i].first;
        int cost = gf[nod][i].second;
        if (viz[vc] == 1) continue;
        initializeaza(vc, nod, cost);//asta inseamna ca primul vecin al lui vc o sa fie nod si o sa aiba costul cost
        dfs(vc, niv+1);
        v[ ++v[0] ] = nod;
    }

}

void preprocesare(){

    //fac matricile Max[i][j] = muchia maxima de pe drumul j, al 2^i-lea tata


    for(int i=1; i<=14; ++i){
        for(int j=1; j<=n; ++j){
            int X = tata[i-1][j];
            tata[i][j] = tata[i-1][X];
            Max[i][j] = max(Max[i-1][j], Max[i-1][X]);
        }
    }

}

void build(int nod, int st, int dr){

    if (st == dr){
        aint[nod] = st;
        return;
    }

    int mij = (st + dr) / 2;
    build(nod*2, st, mij);
    build(nod*2+1, mij+1, dr);

    aint[nod] = aint[nod*2];

    if ( nivel[ v[ aint[nod] ] ] > nivel[ v[ aint[nod*2+1] ] ]){
        aint[nod] = aint[nod*2+1];
    }

}

void query(int nod, int st, int dr, int a, int b, int &nv, int &lca){

    if(a <= st && dr <= b){
        if ( nv > nivel[ v[ aint[nod] ] ] ){
            nv = nivel[ v[ aint[nod] ] ];
            lca = v[ aint[nod] ];
        }
        return;
    }

    int mij = (st + dr) / 2;
    if (a <= mij) query(nod*2, st, mij, a, b, nv, lca);
    if (b > mij) query(nod*2+1, mij+1, dr, a, b, nv, lca);

}

int afla_muchie(int lca, int nod, int bug){

    int k = nivel[nod] - nivel[lca];//aflu al catelea tata e lca pentru nod
    int rez = 0;
    for(int i=14; i>=0; --i){
        if ( ( k &(1<<i) ) != 0 ){//daca am 1
            rez = max(rez, Max[i][nod]);
            nod = tata[i][nod];
        }
    }

    return rez;

}

void rezolva(){

    //am k query-uri de forma (x,y) trebuie sa aleg un drum intre x si y a. i. muchia maxima de pe acel drum sa fie cat mai mica
    // pentru un drum de la x la y costul acelui drum va fi dat de catre muchia maxima
    //ma intereseaza sa gasesc acel drum care are muchia maxima minima = > am nevoie sa refac graful a. i. intre 2 noduri sa existe doar un drum unic
    // iar muchiile de pe drum sa fie cat mai mici asa ca voi transforma graful initial intr-un arbore mai exact unul de cost minim

    fa_APM();

    //acum pentru un drum intre x,y trebuie sa afisez muchia maxima;
    //asa ca impart acest drum in 2 : aflu Lca-ul
    //si aflu cu ajutorul preprocesarii muchia maxima de pe drumul nod1 lca si nod2 lca

    dfs(1, 0);//fac o parcurgere euler a arborelui + intializez matricea de Min si matricea de tata
    build(1, 1, v[0]);//construiesc arborele de intervale pentru LCA

    preprocesare();

    for(int i=1; i<=K; ++i){
        int x, y;
        f >> x >> y;
        //muchia maxima minima de pe drum X, Y;

        //le aflu lca-ul
       int first_X = P[x];
       int first_Y = P[y];
       if (first_X > first_Y) swap(first_X, first_Y);
       int lca = 0;
       int nv = inf;
       query(1, 1, v[0], first_X, first_Y, nv, lca);

       int rez = 0;
       rez = max( rez, afla_muchie(lca, x, 0) );
       rez = max( rez, afla_muchie(lca, y, 1) );
       g << rez << "\n";
    }

}

int main(){

    citeste();
    rezolva();

    f.close();
    g.close();

    return 0;

}