#include #include #include #include #include #include // An implementation of the Disjoint Set Union (DSU) data structure, // also known as Union-Find. class DSU { public: // Initialize each node to be its own parent. DSU(int n) { parent.resize(n + 1); for (int i = 0; i <= n; ++i) { parent[i] = i; } } // Find the root of the set containing element i with path compression. int find(int i) { if (parent[i] == i) { return i; } // Path compression: set the parent of i directly to the root. return parent[i] = find(parent[i]); } // Merge the sets containing elements i and j. // Returns true if a merge happened, false otherwise. bool unite(int i, int j) { int root_i = find(i); int root_j = find(j); if (root_i != root_j) { parent[root_i] = root_j; return true; } return false; } private: std::vector parent; }; // A struct to represent an edge in the graph for Kruskal's algorithm. // The "weight" is the maximum height of its two endpoints. struct Edge { int weight; int u; int v; // Overload the less-than operator to allow sorting of edges by weight. bool operator<(const Edge& other) const { return weight < other.weight; } }; void solve() { // Fast I/O for C++ std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); int n, m; // Gracefully handle potential empty input if (!(std::cin >> n >> m)) { return; } // Adjust heights to be 1-indexed for consistency with hill numbers std::vector heights(n + 1); std::set unique_heights_set; for (int i = 1; i <= n; ++i) { std::cin >> heights[i]; unique_heights_set.insert(heights[i]); } std::vector> adj(n + 1); for (int i = 0; i < m; ++i) { int u, v; std::cin >> u >> v; adj[u].push_back(v); adj[v].push_back(u); } // Create a sorted vector of all unique hill heights std::vector unique_heights(unique_heights_set.begin(), unique_heights_set.end()); // Map heights to the hills that have that height for quick lookup std::map> hills_by_height; for (int i = 1; i <= n; ++i) { hills_by_height[heights[i]].push_back(i); } long long min_diff = std::numeric_limits::max(); std::vector active_edges; std::vector active_hills(n + 1, false); // The core idea: iterate through all possible minimum heights (h_min) // for a valid path, from highest to lowest. for (int l = unique_heights.size() - 1; l >= 0; --l) { int h_min = unique_heights[l]; // Activate all hills that have the current h_min const std::vector& newly_activated_hills = hills_by_height[h_min]; std::vector new_edges; for (int u : newly_activated_hills) { active_hills[u] = true; } // For each newly activated hill, add edges to its active neighbors. for (int u : newly_activated_hills) { for (int v : adj[u]) { if (active_hills[v]) { int weight = std::max(heights[u], heights[v]); new_edges.push_back({weight, u, v}); } } } // Add the new edges to our list and re-sort. active_edges.insert(active_edges.end(), new_edges.begin(), new_edges.end()); std::sort(active_edges.begin(), active_edges.end()); // We can only find a path if both Hill 1 and Hill 2 are active. if (!active_hills[1] || !active_hills[2]) { continue; } // For the current h_min, find the smallest possible h_max that connects // Hill 1 and Hill 2 using Kruskal's algorithm. DSU dsu(n); if (dsu.find(1) != dsu.find(2)) { for (const auto& edge : active_edges) { dsu.unite(edge.u, edge.v); if (dsu.find(1) == dsu.find(2)) { // This edge connected the two components containing Hill 1 and 2. // Its weight is the minimum h_max for the current h_min. int h_max = edge.weight; min_diff = std::min(min_diff, (long long)h_max - h_min); break; // Found best h_max for this h_min } } } } std::cout << min_diff << std::endl; } int main() { solve(); return 0; }