Given a tree with N vertices and N-1 Edges. Let’s define a function F(a, b) which is equal to the minimum edge weight in the path between node a & b. The task is to calculate the product of all such F(a, b). Here a&b are unordered pairs and a!=b.
So, basically, we need to find the value of:
where 0<=i<j<=n-1.
In the input, we will be given the value of N and then N-1 lines follow. Each line contains 3 integers u, v, w denoting edge between node u and v and it’s weight w. Since the product will be very large, output it modulo 10^9+7.
Examples:
Input : N = 4 1 2 1 1 3 3 4 3 2 Output : 12 Given tree is: 1 (1)/ \(3) 2 3 \(2) 4 We will calculate the minimum edge weight between all the pairs: F(1, 2) = 1 F(2, 3) = 1 F(1, 3) = 3 F(2, 4) = 1 F(1, 4) = 2 F(3, 4) = 2 Product of all F(i, j) = 1*3*2*1*1*2 = 12 mod (10^9 +7) =12 Input : N = 5 1 2 1 1 3 3 4 3 2 1 5 4 Output : 288
If we observe carefully then we will see that if there is a set of nodes in which minimum edge weight is w and if we add a node to this set that connects the node with the whole set by an edge of weight W such that W<w then path formed between recently added node to all nodes present in the set will have minimum weight W.
So, here we can apply Disjoint-Set Union concept to solve the problem.
First, sort the data structure according to decreasing weight. Initially assign all nodes as a single set. Now when we merge two sets then do the following:-
Product=(present weight)^(size of set1*size of set2).
We will multiply this product value for all edges of the tree.
Below is the implementation of the above approach:
C++
// C++ Implementation of above approach #include <bits/stdc++.h> using namespace std; #define mod 1000000007 // Function to return (x^y) mod p int power( int x, unsigned int y, int p) { int res = 1; x = x % p; while (y > 0) { if (y & 1) res = (res * x) % p; y = y >> 1; x = (x * x) % p; } return res; } // Declaring size array globally int size[300005]; int freq[300004]; vector<pair< int , pair< int , int > > > edges; // Initializing DSU data structure void initialize( int Arr[], int N) { for ( int i = 0; i < N; i++) { Arr[i] = i; size[i] = 1; } } // Function to find the root of ith // node in the disjoint set int root( int Arr[], int i) { while (Arr[i] != i) { i = Arr[i]; } return i; } // Weighted union using Path Compression void weighted_union( int Arr[], int size[], int A, int B) { int root_A = root(Arr, A); int root_B = root(Arr, B); // size of set A is small than size of set B if (size[root_A] < size[root_B]) { Arr[root_A] = Arr[root_B]; size[root_B] += size[root_A]; } // size of set B is small than size of set A else { Arr[root_B] = Arr[root_A]; size[root_A] += size[root_B]; } } // Function to add an edge in the tree void AddEdge( int a, int b, int w) { edges.push_back({ w, { a, b } }); } // Build the tree void MakeTree() { AddEdge(1, 2, 1); AddEdge(1, 3, 3); AddEdge(3, 4, 2); } // Function to return the required product int MinProduct() { int result = 1; // Sorting the edges with respect to its weight sort(edges.begin(), edges.end()); // Start iterating in decreasing order of weight for ( int i = edges.size() - 1; i >= 0; i--) { // Determine Current edge values int curr_weight = edges[i].first; int Node1 = edges[i].second.first; int Node2 = edges[i].second.second; // Calculate root of each node // and size of each set int Root1 = root(freq, Node1); int Set1_size = size[Root1]; int Root2 = root(freq, Node2); int Set2_size = size[Root2]; // Using the formula int prod = Set1_size * Set2_size; int Product = power(curr_weight, prod, mod); // Calculating final result result = ((result % mod) * (Product % mod)) % mod; // Weighted union using Path Compression weighted_union(freq, size, Node1, Node2); } return result % mod; } // Driver code int main() { int n = 4; initialize(freq, n); MakeTree(); cout << MinProduct(); } |
Java
// Java Implementation of above approach import java.util.ArrayList; import java.util.Collections; public class Product { // to store first vertex, second vertex and weight of // the edge static class Edge implements Comparable<Edge> { int first, second, weight; Edge( int x, int y, int w) { this .first = x; this .second = y; this .weight = w; } @Override public int compareTo(Edge edge) { return this .weight - edge.weight; } } static int mod = 1000000007 ; // Function to return (x^y) mod p static int power( int x, int y, int p) { int res = 1 ; x = x % p; while (y > 0 ) { if ((y & 1 ) == 1 ) res = (res * x) % p; y = y >> 1 ; x = (x * x) % p; } return res; } // Declaring size array globally static int size[] = new int [ 300005 ]; static int freq[] = new int [ 300004 ]; static ArrayList<Edge> edges = new ArrayList<Edge>(); // Initializing DSU data structure static void initialize( int Arr[], int N) { for ( int i = 0 ; i < N; i++) { Arr[i] = i; size[i] = 1 ; } } // Function to find the root of ith // node in the disjoint set static int root( int Arr[], int i) { while (Arr[i] != i) { i = Arr[i]; } return i; } // Weighted union using Path Compression static void weighted_union( int Arr[], int size[], int A, int B) { int root_A = root(Arr, A); int root_B = root(Arr, B); // size of set A is small than size of set B if (size[root_A] < size[root_B]) { Arr[root_A] = Arr[root_B]; size[root_B] += size[root_A]; } // size of set B is small than size of set A else { Arr[root_B] = Arr[root_A]; size[root_A] += size[root_B]; } } // Function to add an edge in the tree static void AddEdge( int a, int b, int w) { edges.add( new Edge(a, b, w)); } // Build the tree static void MakeTree() { AddEdge( 1 , 2 , 1 ); AddEdge( 1 , 3 , 3 ); AddEdge( 3 , 4 , 2 ); } // Function to return the required product static int MinProduct() { int result = 1 ; // Sorting the edges with respect to its weight // ascending order Collections.sort(edges); // Start iterating in decreasing order of weight for ( int i = edges.size() - 1 ; i >= 0 ; i--) { // Determine Current edge values int curr_weight = edges.get(i).weight; int Node1 = edges.get(i).first; int Node2 = edges.get(i).second; // Calculate root of each node // and size of each set int Root1 = root(freq, Node1); int Set1_size = size[Root1]; int Root2 = root(freq, Node2); int Set2_size = size[Root2]; // Using the formula int prod = Set1_size * Set2_size; int Product = power(curr_weight, prod, mod); // Calculating final result result = ((result % mod) * (Product % mod)) % mod; // Weighted union using Path Compression weighted_union(freq, size, Node1, Node2); } return result % mod; } // Driver code public static void main(String[] args) { int n = 4 ; initialize(freq, n); MakeTree(); System.out.println(MinProduct()); } } // This code is contributed by jainlovely450 |
Python3
# Python3 implementation of the approach mod = 1000000007 # Function to return (x^y) mod p def power(x: int , y: int , p: int ) - > int : res = 1 x % = p while y > 0 : if y & 1 : res = (res * x) % p y = y / / 2 x = (x * x) % p return res # Declaring size array globally size = [ 0 ] * 300005 freq = [ 0 ] * 300004 edges = [] # Initializing DSU data structure def initialize(arr: list , N: int ): for i in range (N): arr[i] = i size[i] = 1 # Function to find the root of ith # node in the disjoint set def root(arr: list , i: int ) - > int : while arr[i] ! = i: i = arr[i] return i # Weighted union using Path Compression def weighted_union(arr: list , size: list , A: int , B: int ): root_A = root(arr, A) root_B = root(arr, B) # size of set A is small than size of set B if size[root_A] < size[root_B]: arr[root_A] = arr[root_B] size[root_B] + = size[root_A] # size of set B is small than size of set A else : arr[root_B] = arr[root_A] size[root_A] + = size[root_B] # Function to add an edge in the tree def AddEdge(a: int , b: int , w: int ): edges.append((w, (a, b))) # Build the tree def makeTree(): AddEdge( 1 , 2 , 1 ) AddEdge( 1 , 3 , 3 ) AddEdge( 3 , 4 , 2 ) # Function to return the required product def minProduct() - > int : result = 1 # Sorting the edges with respect to its weight edges.sort(key = lambda a: a[ 0 ]) # Start iterating in decreasing order of weight for i in range ( len (edges) - 1 , - 1 , - 1 ): # Determine Current edge values curr_weight = edges[i][ 0 ] node1 = edges[i][ 1 ][ 0 ] node2 = edges[i][ 1 ][ 1 ] # Calculate root of each node # and size of each set root1 = root(freq, node1) set1_size = size[root1] root2 = root(freq, node2) set2_size = size[root2] # Using the formula prod = set1_size * set2_size product = power(curr_weight, prod, mod) # Calculating final result result = ((result % mod) * (product % mod)) % mod # Weighted union using Path Compression weighted_union(freq, size, node1, node2) return result % mod # Driver Code if __name__ = = "__main__" : # Number of nodes and edges n = 4 initialize(freq, n) makeTree() print (minProduct()) # This code is contributed by # sanjeev2552 |
Javascript
<script> // JavaScript implementation of the approach const mod = 1000000007 // Function to return (x^y) mod p function power(x, y, p){ let res = 1 x %= p while (y > 0){ if (y & 1) res = (res * x) % p y = Math.floor(y / 2) x = (x * x) % p } return res } // Declaring size array globally let size = new Array(300005).fill(0) let freq = new Array(300004).fill(0) let edges = [] // Initializing DSU data structure function initialize(arr, N){ for (let i=0;i<N;i++){ arr[i] = i size[i] = 1 } } // Function to find the root of ith // node in the disjoint set function root(arr, i){ while (arr[i] != i) i = arr[i] return i } // Weighted union using Path Compression function weighted_union(arr, size, A, B){ let root_A = root(arr, A) let root_B = root(arr, B) // size of set A is small than size of set B if (size[root_A] < size[root_B]){ arr[root_A] = arr[root_B] size[root_B] += size[root_A] } // size of set B is small than size of set A else { arr[root_B] = arr[root_A] size[root_A] += size[root_B] } } // Function to add an edge in the tree function AddEdge(a, b, w){ edges.push([w, [a, b]]) } // Build the tree function makeTree(){ AddEdge(1, 2, 1) AddEdge(1, 3, 3) AddEdge(3, 4, 2) } // Function to return the required product function minProduct(){ let result = 1 // Sorting the edges with respect to its weight edges.sort((a,b)=>a[0]-b[0]) // Start iterating in decreasing order of weight for (let i=edges.length - 1;i>=0;i--){ // Determine Current edge values let curr_weight = edges[i][0] let node1 = edges[i][1][0] let node2 = edges[i][1][1] // Calculate root of each node // and size of each set let root1 = root(freq, node1) let set1_size = size[root1] let root2 = root(freq, node2) let set2_size = size[root2] // Using the formula let prod = set1_size * set2_size let product = power(curr_weight, prod, mod) // Calculating final result result = ((result % mod) * (product % mod)) % mod // Weighted union using Path Compression weighted_union(freq, size, node1, node2) } return result % mod } // Driver Code // Number of nodes and edges let n = 4 initialize(freq, n) makeTree() document.write(minProduct(), "</br>" ) // This code is contributed by shinjanpatra </script> |
C#
// C# code for the above approach using System; using System.Collections.Generic; namespace MinimumProductSpanningTree { // to store first vertex, second vertex and weight of // the edge class Edge : IComparable<Edge> { public int First { get ; set ; } public int Second { get ; set ; } public int Weight { get ; set ; } public Edge( int x, int y, int w) { First = x; Second = y; Weight = w; } public int CompareTo(Edge edge) { return Weight - edge.Weight; } } class Program { static readonly int Mod = 1000000007; // Declaring size array globally static readonly int [] Size = new int [300005]; static readonly int [] Freq = new int [300004]; static readonly List<Edge> Edges = new List<Edge>(); // Function to Inialize DSU static void Initialize( int [] arr, int n) { for ( int i = 0; i < n; i++) { arr[i] = i; Size[i] = 1; } } // Function to find the root of ith // node in the disjoint set static int Root( int [] arr, int i) { while (arr[i] != i) { i = arr[i]; } return i; } static void WeightedUnion( int [] arr, int [] size, int a, int b) { int rootA = Root(arr, a); int rootB = Root(arr, b); if (size[rootA] < size[rootB]) { arr[rootA] = arr[rootB]; size[rootB] += size[rootA]; } else { arr[rootB] = arr[rootA]; size[rootA] += size[rootB]; } } static void AddEdge( int a, int b, int w) { Edges.Add( new Edge(a, b, w)); } // Build the tree static void MakeTree() { AddEdge(1, 2, 1); AddEdge(1, 3, 3); AddEdge(3, 4, 2); } // Function to return the required product static int MinProduct() { int result = 1; // Sorting the edges with respect to its weight // ascending order Edges.Sort(); // Start iterating in decreasing order of weight for ( int i = Edges.Count - 1; i >= 0; i--) { // Determine Current edge values int currWeight = Edges[i].Weight; int node1 = Edges[i].First; int node2 = Edges[i].Second; // Calculate root of each node // and size of each set int root1 = Root(Freq, node1); int set1Size = Size[root1]; int root2 = Root(Freq, node2); int set2Size = Size[root2]; // Using the formula int prod = set1Size * set2Size; int product = Power(currWeight, prod, Mod); // Calculating final result result = (result * product) % Mod; // Weighted union using Path Compression WeightedUnion(Freq, Size, node1, node2); } return result; } // Function to return (x^y) mod p static int Power( int x, int y, int p) { int res = 1; x = x % p; while (y > 0) { if ((y & 1) == 1) { res = (res * x) % p; } y = y >> 1; x = (x * x) % p; } return res; } // Driver code static void Main( string [] args) { Initialize(Freq, 300004); MakeTree(); Console.WriteLine(MinProduct()); } } } // This code is contributed by Potta Lokesh |
12
Time Complexity : O(N*logN)
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!