Cod sursa(job #1856569)

Utilizator EpictetStamatin Cristian Epictet Data 25 ianuarie 2017 01:53:49
Problema Radiatie Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 5.08 kb
#include <fstream>
#include <algorithm>
#include <vector>
#include <cstring>

using namespace std;

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

class Edge
{
    public :
        int a, b, c;
        bool operator () (const Edge &nr1, const Edge &nr2) { return (nr1.c < nr2.c); }
} M[30010];
int n, m, k, nr_l;
int R[15010], T[15010]; // Rang, Tata
int W[15010], Level[15010], L[15010], L_Tata[15010], L_Level[15010], L_Dim[15010], L_Pos[15010], AINT[60010];
bool F[15010];
vector < pair < int, int > > G[15010], APM[15010], Path[15010];

int Find(int x)
{
    int y, bos = x;
    while (bos != T[bos]) bos = T[bos];
    while (x != T[x])
    {
        y = T[x];
        T[x] = bos;
        x = y;
    }
    return bos;
}

void Unite(int x, int y)
{
    if (R[x] < R[y])
    {
        T[x] = y;
        R[y] += R[x];
    }
    else
    {
        T[y] = x;
        R[x] += R[y];
    }
}

void DFS(int node)
{
    F[node] = true;
    W[node] = 1;

    int heavy_node = -1, leaf = 1;

    for (vector < pair < int, int > > :: iterator it = APM[node].begin(); it != APM[node].end(); it ++)
    {
        if (!F[it->first])
        {
            leaf = 0;
            Level[it->first] = Level[node] + 1;

            DFS(it->first);

            W[node] += W[it->first];

            if (heavy_node < 0 || W[it->first] > W[heavy_node]) heavy_node = it->first;
        }
    }

    if (leaf)
    {
        nr_l ++;
        L[node] = nr_l;
        L_Dim[nr_l] = 1;
        for (vector < pair < int, int > > :: iterator it = APM[node].begin(); it != APM[node].end(); it ++)
        {
            if (Level[it->first] < Level[node])
            {
                Path[nr_l].push_back( { node, it->second } );
                break;
            }
        }

    }
    else
    {
        int nice = 0;
        L[node] = L[heavy_node];
        L_Dim[L[node]] += 1;
        for (vector < pair < int, int > > :: iterator it = APM[node].begin(); it != APM[node].end(); it ++)
        {
            if (Level[it->first] < Level[node])
            {
                Path[L[node]].push_back( { node, it->second } );
                nice = 1;
                break;
            }
        }
        if (!nice) Path[L[node]].push_back( { node, 0 } );

        for (vector < pair < int, int > > :: iterator it = APM[node].begin(); it != APM[node].end(); it ++)
        {
            if (it->first != heavy_node && Level[it->first] > Level[node])
            {
                L_Tata[L[it->first]] = node;
                L_Level[L[it->first]] = Level[node];
            }
        }
    }
}

inline int Maxim(int const &a, int const &b)
{
    if (a > b) return a;
    return b;
}

void Build_Tree(int node, int left, int right, int decalaj, int lant)
{
    if (left == right)
    {
        AINT[node + decalaj] = Path[lant][left - 1].second;
    }
    else
    {
        int mid = (left + right) / 2;

        Build_Tree(node * 2, left, mid, decalaj, lant);
        Build_Tree(node * 2 + 1, mid + 1, right, decalaj, lant);

        AINT[node + decalaj] = Maxim(AINT[node * 2 + decalaj], AINT[node * 2 + 1 + decalaj]);
    }
}

int Query(int node, int left, int right, int a, int b, int decalaj)
{
    if (a <= left && right <= b)
    {
        return AINT[node + decalaj];
    }
    else
    {
        int mid = (left + right) / 2, ret1 = 0, ret2 = 0;

        if (a <= mid) ret1 = Query(node * 2, left, mid, a, b, decalaj);
        if (b > mid) ret2 = Query(node * 2 + 1, mid + 1, right, a, b, decalaj);

        return Maxim(ret1, ret2);
    }
}

int main()
{
    fin >> n >> m >> k;
    for (int i = 1; i <= m; i ++)
    {
        fin >> M[i].a >> M[i].b >> M[i].c;
        G[M[i].a].push_back( { M[i].b, M[i].c } );
        G[M[i].b].push_back( { M[i].a, M[i].c } );
    }
    sort(M + 1, M + 1 + m, Edge());
    for (int i = 1; i <= n; i ++)
    {
        R[i] = 1;
        T[i] = i;
    }
    for (int i = 1; i <= m; i ++)
    {
        int f1 = Find(M[i].a);
        int f2 = Find(M[i].b);
        if (f1 != f2)
        {
            Unite(f1, f2);
            APM[M[i].a].push_back( { M[i].b, M[i].c } );
            APM[M[i].b].push_back( { M[i].a, M[i].c } );
        }
    }
    Level[1] = 1;
    DFS(1);
    for (int i = 1; i <= nr_l; i ++)
    {
        reverse(Path[i].begin(), Path[i].end());
        if (i > 1) L_Pos[i] = L_Pos[i - 1] + L_Dim[i - 1] * 4;
        Build_Tree(1, 1, L_Dim[i], L_Pos[i], i);
    }
    for (int a, b, i = 1; i <= k; i ++)
    {
        fin >> a >> b;
        int sol = 0;
        while (L[a] != L[b])
        {
            if (L_Level[L[a]] < L_Level[L[b]]) a ^= b ^= a ^= b;
            sol = Maxim(sol, Query(1, 1, L_Dim[L[a]], 1, Level[a] - L_Level[L[a]], L_Pos[L[a]]));
            a = L_Tata[L[a]];
        }
        if (Level[a] > Level[b]) a ^= b ^= a ^= b;
        sol =  Maxim(sol, Query(1, 1, L_Dim[L[a]], Level[a] - L_Level[L[a]] + 1, Level[b] - L_Level[L[a]], L_Pos[L[a]]));
        fout << sol << '\n';
    }
    fout.close();
    return 0;
}