
'''simple docstring'''







from math import factorial







def 				SCREAMING_SNAKE_CASE__	(   __A			,				__A			,				__A	)       ->	float:
	if successes > trials:
		raise ValueError('successes must be lower or equal to trials'	)
	if trials < 0 or successes < 0:
		raise ValueError('the function is defined for non-negative integers'	)
	if not isinstance(__A			,				__A	) or not isinstance(__A			,				__A	):
		raise ValueError('the function is defined for non-negative integers'	)
	if not 0 < prob < 1:
		raise ValueError('prob has to be in range of 1 - 0'	)
	_snake_case   						=		(prob**successes) * ((1 - prob) ** (trials - successes))
	# Calculate the binomial coefficient: n! / k!(n-k)!
	_snake_case   						=		float(factorial(__A	)	)
	coefficient /= factorial(__A	) * factorial(trials - successes	)
	return probability * coefficient


if __name__ == "__main__":
					from doctest import testmod

					testmod()
					print("Probability of 2 successes out of 4 trails")
					print("with probability of 0.75 is:", end=" ")
					print(binomial_distribution(2, 4, 0.75))


"""simple docstring"""




from __future__ import annotations

from typing import Generic, TypeVar

__lowerCamelCase							 =     TypeVar("T")
class 			UpperCamelCase__(	Generic[T]       ):





						def __init__(				self						,__UpperCAmelCase   )    -> None:
													A__		   =							data
													A__		   =							self
													A__		   =							0






class 			UpperCamelCase__(	Generic[T]       ):





						def __init__(				self   )    -> None:
													# map from node name to the node object
													A__		   =							{}





						def  snake_case__		(				self						,__UpperCAmelCase   )    -> None:
													# create a new set with x as its member
													A__		   =							DisjointSetTreeNode(__UpperCAmelCase   )





						def  snake_case__		(				self						,__UpperCAmelCase   )    -> DisjointSetTreeNode[T]:
													# find the set x belongs to (with path-compression)
													A__		   =							self.map[data]
													if elem_ref != elem_ref.parent:
																				A__		   =							self.find_set(elem_ref.parent.data   )
													return elem_ref.parent





						def  snake_case__		(				self						,__UpperCAmelCase						,__UpperCAmelCase   )    -> None:
													# helper function for union operation
													if nodea.rank > nodea.rank:
																				A__		   =							nodea
													else:
																				A__		   =							nodea
																				if nodea.rank == nodea.rank:
																											nodea.rank += 1





						def  snake_case__		(				self						,__UpperCAmelCase						,__UpperCAmelCase   )    -> None:
													# merge 2 disjoint sets
													self.link(self.find_set(__UpperCAmelCase   )						,self.find_set(__UpperCAmelCase   )   )






class 			UpperCamelCase__(	Generic[T]       ):





						def __init__(				self   )    -> None:
													# connections: map from the node to the neighbouring nodes (with weights)
													A__		   =							{}





						def  snake_case__		(				self						,__UpperCAmelCase   )    -> None:
													# add a node ONLY if its not present in the graph
													if node not in self.connections:
																				A__		   =							{}





						def  snake_case__		(				self						,__UpperCAmelCase						,__UpperCAmelCase						,__UpperCAmelCase   )    -> None:
													# add an edge with the given weight
													self.add_node(__UpperCAmelCase   )
													self.add_node(__UpperCAmelCase   )
													A__		   =							weight
													A__		   =							weight





						def  snake_case__		(				self   )    -> GraphUndirectedWeighted[T]:
													A__		   =							[]
													A__		   =							set()
													for start in self.connections:
																				for end in self.connections[start]:
																											if (start, end) not in seen:
																																		seen.add((end, start)   )
																																		edges.append((start, end, self.connections[start][end])   )
													edges.sort(key=lambda __UpperCAmelCase   : x[2]   )

													# creating the disjoint set
													A__		   =							DisjointSetTree[T]()
													for node in self.connections:
																				disjoint_set.make_set(__UpperCAmelCase   )

													# MST generation
													A__		   =							0
													A__		   =							0
													A__		   =							GraphUndirectedWeighted[T]()
													while num_edges < len(self.connections   ) - 1:
																				A__   ,     A__   ,     A__		   =							edges[index]
																				index += 1
																				A__		   =							disjoint_set.find_set(__UpperCAmelCase   )
																				A__		   =							disjoint_set.find_set(__UpperCAmelCase   )
																				if parent_u != parent_v:
																											num_edges += 1
																											graph.add_edge(__UpperCAmelCase						,__UpperCAmelCase						,__UpperCAmelCase   )
																											disjoint_set.union(__UpperCAmelCase						,__UpperCAmelCase   )
													return graph





