Cod sursa(job #1959328)

Utilizator AkrielAkriel Akriel Data 9 aprilie 2017 13:06:41
Problema Radiatie Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 6.25 kb
#include <bits/stdc++.h>

using namespace std;

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

const int N = 15005;
const int M = 2*N;
const int D = 15;
const int infinite = 1<<30;

int totalNodes, totalEdges, totalQuestions;

int root[N], parent[N], normalized[N], costs[N],
    firstAppearance[N], lastAppearance[N], answers[N],
    deepFirstSearchChart[N], dynamic[N];

int rangeMaximum[D][N];

int arbore[4*M];

int contor, queryLeft, queryRight;

tuple <int, int, int> edges[M]; // cost, origin, destination

vector <int> nodes[N];

vector <int> eulerChart;

vector <pair <int, int> > questions[N];

bitset <M> used;

int getRoot(int node){
    if ( node == root[node] )
        return node;
    root[node] = getRoot(root[node]);
    return root[node];
}

int commonAncestor(int position = 1, int left = 1, int right = eulerChart.size()){
    if ( left > queryRight or right < queryLeft )
        return infinite;
    if ( queryLeft <= left and right <= queryRight )
        return arbore[position];
    int middle = (left+right)/2;
    return min( commonAncestor(2*position, left, middle), commonAncestor(2*position+1, middle+1, right) );
}

int getMax(int first, int second){
    if ( first < second )
        return -infinite;
    int currentDepth = log2(first - second + 1);
    return max(rangeMaximum[currentDepth][deepFirstSearchChart[first]], rangeMaximum[currentDepth][deepFirstSearchChart[second+(1<<currentDepth)-1]]);
}

inline void readVariables(){
    fin >> totalNodes >> totalEdges >> totalQuestions;

    int origin, destination, cost;
    for ( int index = 1; index <= totalEdges; index++ ){
        fin >> origin >> destination >> cost;
        edges[index] = make_tuple(cost, origin, destination);
    }
}

inline void initializeRangeMaximum(){
    for ( int depth = 1; depth < D; depth++ )
        for ( int index = 1; index <= totalNodes; index++ )
            rangeMaximum[depth][index] = -infinite;
    costs[1] = -infinite;
}

inline void partiallyArbore(){
    for ( int index = 1; index <= totalNodes; index++ )
        root[index] = index;
    sort(edges+1, edges+totalEdges+1);

    int origin, destination, cost;
    for ( int index = 1; index <= totalEdges; index++ ){
        tie(cost, origin, destination) = edges[index];
        int rootOrigin = getRoot(origin),
            rootDestination = getRoot(destination);

        if ( rootDestination != rootOrigin ){
            nodes[origin].push_back(destination);
            nodes[destination].push_back(origin);
            used[index] = true;
            root[rootOrigin] = root[rootDestination];
        }
    }
}

void liniarize(int currentNode = 1, int source = 0){
    contor++;
    parent[currentNode] = source;
    normalized[currentNode] = contor;

    for ( auto it : nodes[currentNode] )
        if ( it != source )
            liniarize(it, currentNode);
}

inline void determinateCosts(){
    int origin, destination, cost;
    for ( int index = 1; index <= totalEdges; index++ ){
        if ( used[index] ){
            tie(cost, origin, destination) = edges[index];
            if ( parent[destination] == origin )
                costs[destination] = cost;
            else
                costs[origin] = cost;
        }
    }
}

void eulerSearch(int currentNode = 1, int source = 0){
    int index = normalized[currentNode];
    eulerChart.push_back(index);
    firstAppearance[index] = eulerChart.size();
    for ( auto it : nodes[currentNode] ){
        if ( it != source ){
            eulerSearch(it, currentNode);
            eulerChart.push_back(index);
        }
    }
    lastAppearance[index] = eulerChart.size();
}

void buildIntervals(int position = 1, int left = 1, int right = eulerChart.size()){
    if ( left == right ){
        arbore[position] = eulerChart[left-1];
        return;
    }
    int middle = (left+right)/2;
    buildIntervals(2*position, left, middle);
    buildIntervals(2*position+1, middle+1, right);
    arbore[position] = min(arbore[2*position], arbore[2*position+1]);
}

inline void readQuery(){
    int firstNode, secondNode;
    for ( int index = 1; index <= totalQuestions; index++ ){
        answers[index] = -infinite;
        fin >> firstNode >> secondNode;
        firstNode = normalized[firstNode];
        secondNode = normalized[secondNode];
        if ( firstAppearance[firstNode] > lastAppearance[secondNode] )
            swap(firstNode, secondNode);
        queryLeft = firstAppearance[firstNode];
        queryRight = lastAppearance[secondNode];
        int lowestCommonAncestor = commonAncestor();
        questions[firstNode].push_back({lowestCommonAncestor, index});
        questions[secondNode].push_back({lowestCommonAncestor, index});
    }
}

void deepFirstSearch(int currentNode = 1, int source = 0, int depth = 1){
    int index = normalized[currentNode];
    deepFirstSearchChart[depth] = index;
    dynamic[index] = depth;
    rangeMaximum[0][index] = costs[currentNode];

    for ( int indexDepth = 1; (1<<indexDepth) <= depth; indexDepth++ )
        rangeMaximum[indexDepth][index] = max(rangeMaximum[indexDepth-1][index], rangeMaximum[indexDepth-1][deepFirstSearchChart[depth-(1<<(indexDepth-1))]]);

    for ( auto it : questions[index] ){
        int aux = getMax(dynamic[index], dynamic[it.first] + 1);
        answers[it.second] = max(answers[it.second], aux);
    }

    for ( auto it : nodes[currentNode] )
        if ( it != source )
            deepFirstSearch(it, currentNode, depth+1);
}

inline void printSolution(){
    for ( int index = 1; index <= totalQuestions; index++ )
        fout << answers[index] << "\n";
}

inline void debuggingPurposes(){
    for ( auto it : eulerChart )
        cout << it << " ";
    cout << "\n\n";
    for ( int index = 1; index <= totalNodes*4; index++ )
        cout << arbore[index] << " ";
    cout << "\n\n";
    for ( int index = 1; index <= totalNodes; index++ )
        cout << dynamic[index] << " ";
}

int main(){
    readVariables();
    initializeRangeMaximum();
    partiallyArbore();
    liniarize();
    determinateCosts();
    eulerSearch();
    buildIntervals();
    readQuery();
    deepFirstSearch();
    printSolution();
    return 0;
}