Cod sursa(job #2712334)

Utilizator BAlexandruBorgovan Alexandru BAlexandru Data 25 februarie 2021 17:38:27
Problema Radiatie Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 6.01 kb
#include <fstream>
#include <vector>
#include <algorithm>

using namespace std;

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

const int INF = 2e9;

class minHeap
{
    private:
        struct heapElement
        {
            int key;
            int value;
        };

        heapElement *harr;
        int *pos;
        int capacity;
        int heapSize;

    public:
        minHeap(int cap, int maxKey);
        ~minHeap();

        int parent(int node) {return node / 2;}
        int leftChild(int node) {return node * 2;}
        int rightChild(int node) {return node * 2 + 1;}

        void heapifyUp(int node);
        void heapifyDown(int node);

        int getMin();
        void extractMin();

        void insertElement(int key, int value);
        void decreaseKey(int key, int newValue);
};

minHeap :: minHeap(int cap, int maxKey)
{
    harr = new heapElement[cap + 1];
    pos = new int[maxKey + 1];
    capacity = cap;
    heapSize = 0;
}

minHeap :: ~minHeap()
{
    delete[] harr;
    delete[] pos;
}

void minHeap :: heapifyUp(int node)
{
    while (node > 1 && harr[node].value < harr[parent(node)].value)
    {
        swap(pos[harr[node].key], pos[harr[parent(node)].key]);
        swap(harr[node], harr[parent(node)]);
        node = parent(node);
    }
}

void minHeap :: heapifyDown(int node)
{
    int child = 0;
    do
    {
        child = 0;

        if (leftChild(node) <= heapSize)
        {
            child = leftChild(node);

            if (rightChild(node) <= heapSize && harr[rightChild(node)].value < harr[leftChild(node)].value)
                child = rightChild(node);

            if (harr[child].value >= harr[node].value)
                child = 0;
        }

        if (child)
        {
            swap(pos[harr[node].key], pos[harr[child].key]);
            swap(harr[node], harr[child]);
            node = child;
        }

    }while (child);
}

int minHeap :: getMin()
{
    return harr[1].key;
}

void minHeap :: extractMin()
{
    if (!heapSize)
        return;

    pos[harr[1].key] = 0;

    harr[1] = harr[heapSize];
    pos[harr[1].key] = 1;
    heapSize--;

    heapifyDown(1);
}

void minHeap :: insertElement(int key, int value)
{
    if (heapSize == capacity)
        return;

    heapSize++;
    harr[heapSize].key = key;
    harr[heapSize].value = value;
    pos[key] = heapSize;

    heapifyUp(heapSize);
}

void minHeap :: decreaseKey(int key, int newValue)
{
    if (!pos[key])
        return;

    harr[pos[key]].value = newValue;
    heapifyUp(pos[key]);
}


struct edge
{
    int node;
    int dist;

    edge()
    {
        node = 0;
        dist = 0;
    }

    edge(int _NODE, int _DIST)
    {
        node = _NODE;
        dist = _DIST;
    }
};


void prim(int V, const vector < edge > (&adj)[15001], vector < edge > (&newAdj)[15001])
{
    bool *used = new bool[V + 1];
    int *dist = new int[V + 1];
    int *parent = new int[V + 1];

    int root = 1;

    for (int i=1; i<=V; i++)
    {
        used[i] = false;
        dist[i] = INF;
    }

    used[root] = true;
    for (auto it : adj[root])
    {
        dist[it.node] = it.dist;
        parent[it.node] = root;
    }

    minHeap h(V, V);
    for (int i=1; i<=V; i++)
        if (i != root)
            h.insertElement(i, dist[i]);

    for (int i=1; i<V; i++)
    {
        int node = h.getMin();
        h.extractMin();

        used[node] = true;

        newAdj[node].push_back(edge(parent[node], dist[node]));
        newAdj[parent[node]].push_back(edge(node, dist[node]));

        for (auto it : adj[node])
            if (!used[it.node] && it.dist < dist[it.node])
            {
                dist[it.node] = it.dist;
                parent[it.node] = node;
                h.decreaseKey(it.node, it.dist);
            }
    }

    delete[] used;
    delete[] dist;
    delete[] parent;
}

int n, m, k;

int log2[15001];

int depth[15001];

pair < int, int > dp[15001][14];

vector < edge > graph[15001];
vector < edge > tree[15001];

void dfs(const vector < edge > (&adj)[15001], int node, edge toParent, int d)
{
    depth[node] = d;

    dp[node][0].first = toParent.node;
    dp[node][0].second = toParent.dist;

    for (auto it : adj[node])
        if (it.node != toParent.node)
            dfs(adj, it.node, edge(node, it.dist), d + 1);
}

int maxDist(const vector < edge > (&adj)[15001], int node1, int node2)
{
    if (node1 == node2)
        return 0;

    if (depth[node1] < depth[node2])
        swap(node1, node2);

    int maxDist = 0;

    for (int i=log2[depth[node1]]; i>=0; i--)
        if (depth[node1] - (1<<i) >= depth[node2])
        {
            maxDist = max(maxDist, dp[node1][i].second);
            node1 = dp[node1][i].first;
        }

    if (node1 == node2)
        return maxDist;

    for (int i=log2[depth[node1]]; i>=0; i--)
        if (dp[node1][i].first && dp[node1][i].first != dp[node2][i].first)
        {
            maxDist = max(maxDist, max(dp[node1][i].second, dp[node2][i].second));
            node1 = dp[node1][i].first;
            node2 = dp[node2][i].first;
        }

    maxDist = max(maxDist, max(dp[node1][0].second, dp[node2][0].second));

    return maxDist;
}

int main()
{
    f >> n >> m >> k;

    for (int i=1; i<=m; i++)
    {
        int a, b, c; f >> a >> b >> c;
        graph[a].push_back(edge(b, c));
        graph[b].push_back(edge(a, c));
    }

    prim(n, graph, tree);

    dfs(tree, 1, edge(0, 0), 0);

    for (int i=1; (1<<i)<=n; i++)
        for (int j=1; j<=n; j++)
        {
            dp[j][i].first = dp[dp[j][i-1].first][i-1].first;
            dp[j][i].second = max(dp[j][i-1].second, dp[dp[j][i-1].first][i-1].second);
        }

    for (int i=2; i<=n; i++)
        log2[i] = log2[i/2] + 1;

    while (k--)
    {
        int x, y; f >> x >> y;
        g << maxDist(tree, x, y) << "\n";
    }

    return 0;
}