






from __future__ import annotations

from collections.abc import Callable
from typing import Generic, TypeVar

lowercase  							=					TypeVar("T")
lowercase  							=					TypeVar("U")




class  UpperCamelCase_      (			Generic[T, U]				):



	'''simple docstring'''




	def __init__(       self       ,			a       ,			a					)       ->    Dict:
								snake_case_				=							key
								snake_case_				=							val
								snake_case_				=							None
								snake_case_				=							None






	def __repr__(       self					)       ->    str:
								return (
								    F'''Node: key: {self.key}, val: {self.val}, '''
								    F'''has next: {bool(self.next					)}, has prev: {bool(self.prev					)}'''
								)






class  UpperCamelCase_      (			Generic[T, U]				):



	'''simple docstring'''




	def __init__(       self					)       ->    None:
								snake_case_				=							DoubleLinkedListNode(a       ,			a					)
								snake_case_				=							DoubleLinkedListNode(a       ,			a					)
								snake_case_			,		snake_case_				=							self.rear, self.head




	def __repr__(       self					)       ->    str:
								snake_case_				=							['DoubleLinkedList']
								snake_case_				=							self.head
								while node.next is not None:
															rep.append(str(a					)					)
															snake_case_				=							node.next
								rep.append(str(self.rear					)					)
								return ",\n    ".join(a					)




	def 							_UpperCamelCase			(       self       ,			a					)       ->    None:
								snake_case_				=							self.rear.prev

								# All nodes other than self.head are guaranteed to have non-None previous
								assert previous is not None

								snake_case_				=							node
								snake_case_				=							previous
								snake_case_				=							node
								snake_case_				=							self.rear






	def 							_UpperCamelCase			(       self       ,			a					)       ->    DoubleLinkedListNode[T, U] | None:

								if node.prev is None or node.next is None:
															return None

								snake_case_				=							node.next
								snake_case_				=							node.prev
								snake_case_				=							None
								snake_case_				=							None
								return node






class  UpperCamelCase_      (			Generic[T, U]				):



	'''simple docstring'''




	lowerCAmelCase													= {}




	def __init__(       self       ,			a					)       ->    Union[str, Any]:
								snake_case_				=							DoubleLinkedList()
								snake_case_				=							capacity
								snake_case_				=							0
								snake_case_				=							0
								snake_case_				=							0
								snake_case_				=							{}




	def __repr__(       self					)       ->    str:
								return (
								    F'''CacheInfo(hits={self.hits}, misses={self.miss}, '''
								    F'''capacity={self.capacity}, current size={self.num_keys})'''
								)




	def __contains__(       self       ,			a					)       ->    bool:
								return key in self.cache




	def 							_UpperCamelCase			(       self       ,			a					)       ->    U | None:
								# Note: pythonic interface would throw KeyError rather than return None

								if key in self.cache:
															self.hits += 1
															snake_case_				=							self.cache[key]
															snake_case_				=							self.list.remove(self.cache[key]					)
															assert node == value_node

															# node is guaranteed not None because it is in self.cache
															assert node is not None
															self.list.add(a					)
															return node.val
								self.miss += 1
								return None




	def 							_UpperCamelCase			(       self       ,			a       ,			a					)       ->    None:

								if key not in self.cache:
															if self.num_keys >= self.capacity:
																						# delete first node (oldest) when over capacity
																						snake_case_				=							self.list.head.next

																						# guaranteed to have a non-None first node when num_keys > 0
																						# explain to type checker via assertions
																						assert first_node is not None
																						assert first_node.key is not None
																						assert (
																						    self.list.remove(a					) is not None
																						)  # node guaranteed to be in list assert node.key is not None

																						del self.cache[first_node.key]
																						self.num_keys -= 1
															snake_case_				=							DoubleLinkedListNode(a       ,			a					)
															self.list.add(self.cache[key]					)
															self.num_keys += 1

								else:
															# bump node to the end of the list, update value
															snake_case_				=							self.list.remove(self.cache[key]					)
															assert node is not None  # node guaranteed to be in list
															snake_case_				=							value
															self.list.add(a					)






	@classmethod
	def 							_UpperCamelCase			(       cls       ,			a = 1_28					)       ->    Callable[[Callable[[T], U]], Callable[..., U]]:

								def cache_decorator_inner(a					) -> Callable[..., U]:
															def cache_decorator_wrapper(*a					) -> U:
																						if func not in cls.decorator_function_to_instance_map:
																													snake_case_				=							LRUCache(a					)

																						snake_case_				=							cls.decorator_function_to_instance_map[func].get(args[0]					)
																						if result is None:
																													snake_case_				=							func(*a					)
																													cls.decorator_function_to_instance_map[func].put(args[0]       ,			a					)
																						return result

															def cache_info() -> LRUCache[T, U]:
																						return cls.decorator_function_to_instance_map[func]

															setattr(a       ,			'cache_info'       ,			a					)  # noqa: B010

															return cache_decorator_wrapper

								return cache_decorator_inner


if __name__ == "__main__":
	import doctest

	doctest.testmod()













class  UpperCamelCase_      :



	'''simple docstring'''




	def __init__(       self       ,			a					)       ->    None:
								snake_case_				=							set_counts
								snake_case_				=							max(a					)
								snake_case_				=							len(a					)
								snake_case_				=							[1] * num_sets
								snake_case_				=							list(range(a					)					)




	def 							_UpperCamelCase			(       self       ,			a       ,			a					)       ->    bool:
								snake_case_				=							self.get_parent(a					)
								snake_case_				=							self.get_parent(a					)

								if src_parent == dst_parent:
															return False

								if self.ranks[dst_parent] >= self.ranks[src_parent]:
															self.set_counts[dst_parent] += self.set_counts[src_parent]
															snake_case_				=							0
															snake_case_				=							dst_parent
															if self.ranks[dst_parent] == self.ranks[src_parent]:
																						self.ranks[dst_parent] += 1
															snake_case_				=							self.set_counts[dst_parent]
								else:
															self.set_counts[src_parent] += self.set_counts[dst_parent]
															snake_case_				=							0
															snake_case_				=							src_parent
															snake_case_				=							self.set_counts[src_parent]

								snake_case_				=							max(self.max_set       ,			a					)
								return True






	def 							_UpperCamelCase			(       self       ,			a					)       ->    int:
								if self.parents[disj_set] == disj_set:
															return disj_set
								snake_case_				=							self.get_parent(self.parents[disj_set]					)
								return self.parents[disj_set]





