Cod sursa(job #2393136)

Utilizator IulianOleniucIulian Oleniuc IulianOleniuc Data 30 martie 2019 21:42:23
Problema Radiatie Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.92 kb
#include <vector>
#include <fstream>
#include <algorithm>

using std::vector;
using std::pop_heap;
using std::make_heap;

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

inline int max(int x, int y) {
    return x > y ? x : y;
}

inline void swap(int& x, int& y) {
    int aux = x;
    x = y;
    y = aux;
}

int log2(int x) {
    for (int i = 31; i >= 0; i--)
        if (x & (1 << i))
            return i;
    return 0;
}

struct Edge {
    int x, y;
    int cost;
};

inline bool operator<(Edge x, Edge y) {
    return x.cost > y.cost;
}

class Forest {
  private:
    vector<int> height;
    vector<int> father;

  public:
    Forest(int n) {
        height.resize(n + 1);
        father.resize(n + 1);
    }

    int find(int x) {
        int root = x;
        while (father[root])
            root = father[root];

        int aux;
        while (father[x]) {
            aux = father[x];
            father[x] = root;
            x = aux;
        }
        return root;
    }

    void unite(int rootX, int rootY) {
        if (height[rootX] < height[rootY])
            father[rootX] = rootY;
        else {
            father[rootY] = rootX;
            if (height[rootX] == height[rootY])
                height[rootX]++;
        }
    }
};

class Tree {
  private:
    struct Node {
        int node, cost;
        Node(int node = 0, int cost = 0) {
            this->node = node;
            this->cost = cost;
        }
    };

    int n;
    vector<Node> father;
    vector<vector<Node>> ad;

    int height;
    vector<int> level;

    vector<vector<int>> anc;
    vector<vector<int>> len;

    int nthAnc(int node, int n) {
        if (n > level[node])
            return 0;

        int k = node;
        for (int i = 31; i >= 0; i--)
            if (n & (1 << i))
                k = anc[k][i];
        return k;
    }

    void dfs(int node, int dad) {
        for (Node nghb : ad[node])
            if (nghb.node != dad) {
                level[nghb.node] = level[node] + 1;
                height = max(height, level[nghb.node]);
                father[nghb.node] = Node(node, nghb.cost);
                dfs(nghb.node, node);
            }
    }

  public:
    Tree(int n) {
        this->n = n;
        ad.resize(n + 1);
    }

    void addEdge(Edge edge) {
        ad[edge.x].push_back(Node(edge.y, edge.cost));
        ad[edge.y].push_back(Node(edge.x, edge.cost));
    }

    void dp() {
        father.resize(n + 1);
        level.resize(n + 1);

        height = 0;
        dfs(1, 0);

        int log = log2(height);
        anc = vector<vector<int>>(n + 1, vector<int>(log));
        len = vector<vector<int>>(n + 1, vector<int>(log));

        for (int i = 1; i <= n; i++) {
            anc[i][0] = father[i].node;
            len[i][0] = father[i].cost;
        }

        for (int j = 1; j <= log; j++)
            for (int i = 1; i <= n; i++) {
                anc[i][j] = anc[anc[i][j - 1]][j - 1];
                len[i][j] = max(len[i][j - 1], len[anc[i][j - 1]][j - 1]);
            }
    }

    int query(int x, int y) {
        if (level[x] > level[y])
            swap(x, y);

        int sol = father[y].cost;
        if (level[y] > level[x]) {
            int z = level[y] - level[x];
            for (int i = 31; i >= 0; i--)
                if (z & (1 << i)) {
                    sol = max(sol, len[y][i]);
                    y = anc[y][i];
                }
        }

        if (x == y)
            return sol;

        int lo = 0, hi = level[x] + 1;
        while (hi - lo > 1) {
            int md = (lo + hi) >> 1;
            if (nthAnc(x, md) == nthAnc(y, md))
                hi = md;
            else
                lo = md;
        }

        for (int i = 31; i >= 0; i--)
            if (hi & (1 << i)) {
                sol = max(sol, len[x][i]); x = anc[x][i];
                sol = max(sol, len[y][i]); y = anc[y][i];
            }
        return sol;
    }
};

Tree kruskal(int n, vector<Edge>& edges) {
    Forest forest(n);
    make_heap(edges.begin(), edges.end());

    Tree mst(n);
    for (int i = 1; i < n; ) {
        Edge edge = edges[0];
        pop_heap(edges.begin(), edges.end());
        edges.pop_back();

        int rootX = forest.find(edge.x);
        int rootY = forest.find(edge.y);

        if (rootX != rootY) {
            i++;
            mst.addEdge(edge);
            forest.unite(rootX, rootY);
        }
    }
    return mst;
}

int main() {
    int n, m, k;
    fin >> n >> m >> k;

    vector<Edge> edges(m);
    for (int i = 0; i < m; i++)
        fin >> edges[i].x >> edges[i].y >> edges[i].cost;

    Tree mst = kruskal(n, edges);
    mst.dp();

    for (int i = 0; i < k; i++) {
        int x, y; fin >> x >> y;
        fout << mst.query(x, y) << '\n';
    }

    fout.close();
    return 0;
}