import itertools import heapq as hq from collections import defaultdict from typing import * T = TypeVar('T') INF = 2 ** 62 min2 = lambda x,y: x if x < y else y class BaseWeightedGraph: def __init__(self, n_vertices: int): self.n_vertices = n_vertices def wadj(self, v: int) -> Iterable[Tuple[int, Any]]: """ Return an iterable of vertices adjacent to v and edge weight """ raise NotImplementedError def adj(self, v: int) -> Iterable[int]: """ Return an iterable of vertices adjacent to v """ return (u for u, w in self.wadj(v)) @property def wedges(self) -> Iterable[Tuple[int, int, Any]]: """ Return an iterable of weighted edges (vertex_1, vertex_2, weight) """ return ((v, u, w) for v in range(self.n_vertices) for u, w in self.wadj(v)) @property def edges(self): return ((v, u) for v in range(self.n_vertices) for u in self.adj(v)) def dist(self, s: int, t: int, inf=INF): return dijkstra(self, s, t, inf)[t] def warshall_floyd(self, inf=INF): pass def to_wgraph(self) -> 'WeightedGraph': return WeightedGraph.from_directed_edges(self.n_vertices, self.wedges) def to_reverse_wgraph(self) -> 'WeightedGraph': return WeightedGraph.from_directed_edges(self.n_vertices, ((u, v, w) for v, u, w in self.wedges)) def to_graph(self) -> 'Graph': l = [[] for _ in range(self.n_vertices)] for u, v in self.edges: l[u].append(v) return Graph.from_lil_adj(self.n_vertices, l) def to_reverse_graph(self) -> 'Graph': l = [[] for _ in range(self.n_vertices)] for u, v in self.edges: l[v].append(u) return Graph.from_lil_adj(self.n_vertices, l) class WeightedGraph(BaseWeightedGraph): def __init__(self, n_vertices: int, adj: List[int], weight: List[Any], ind: List[int]): super().__init__(n_vertices) self._adj = adj self._weight = weight self._ind = ind @classmethod def from_lil_adj(cls, n_vertices: int, adj_list: Iterable[Sequence[Tuple[int, Any]]], n_edges: int) -> 'WeightedGraph': adj = [0] * n_edges weight = [0] * n_edges ind = [0] * (n_vertices + 1) i = 0 for u, l in enumerate(adj_list): ind[u] = i for v, w in l: adj[i] = v weight[i] = w i += 1 ind[n_vertices] = i return cls(n_vertices, adj, weight, ind) @classmethod def from_directed_edges(cls, n_vertices: int, edges: Iterable[Tuple[int, int, int]]) -> 'WeightedGraph': temp = [[] for _ in range(n_vertices)] n_edges = 0 for u, v, w in edges: temp[u].append((v, w)) n_edges += 1 return cls.from_lil_adj(n_vertices, temp, n_edges) @classmethod def from_undirected_edges(cls, n_vertices: int, edges: Iterable[Tuple[int, int, int]]) -> 'WeightedGraph': return cls.from_directed_edges(n_vertices, itertools.chain(edges, ((u, v, w) for v, u, w in edges))) def wadj(self, v: int) -> Iterable[Tuple[int, Any]]: i, j = self._ind[v], self._ind[v + 1] return ((self._adj[k], self._weight[k]) for k in range(i, j)) class ModifiableWeightedGraph(BaseWeightedGraph): def __init__(self, n_vertices: int, edges: MutableMapping[Tuple[int, int], Any]): super().__init__(n_vertices) self._edges = edges temp = [set() for _ in range(n_vertices)] for u, v, w in edges: temp[u].add((v, w)) self._adj = temp @classmethod def from_directed_edges(cls, n_vertices: int, edges: Iterable[Tuple[int, int, Any]]) -> 'ModifiableWeightedGraph': return cls(n_vertices, edges) @classmethod def from_undirected_edges(cls, n_vertices: int, edges: Iterable[Tuple[int, int, Any]]) -> 'ModifiableWeightedGraph': return cls.from_directed_edges(n_vertices, itertools.chain(edges, ((u, v, w) for v, u, w in edges))) def wadj(self, v: int) -> Iterable[Tuple[int, Any]]: return self._adj[v] def update_edge(self, v: int, u: int, w: Any) -> None: try: w_old = self._edges[v, u] self._edges[v, u] = w self._adj[v].discard((u, w_old)) self._adj[v].add((u, w)) except KeyError: self._edges[v, u] = w self._adj[v].add((u, w)) def delete_edge(self, v: int, u: int) -> None: try: w = self._edges[v, u] del self._edges[v, u] self._adj[v].discard((u, w)) except KeyError: pass class BaseGraph(BaseWeightedGraph): def adj(self, v): raise NotImplementedError def wadj(self, v): return ((u, 1) for u in self.adj(v)) def dist(self, s: int, t: int, inf: Any = INF): d = bfs(s, t)[t] return inf if d == -1 else d def furthest_vertex(self, v0): """ Returns a vertex that is furthest away from v0, and its distance from v0 """ q = [v0] visited = [0] * self.n_vertices visited[v0] = 1 x = -1 rd = 0 for d in itertools.count(): if not q: rd = d break x = q[0] nq = [] for v in q: for u in self.adj(v): if not visited[u]: visited[u] = 1 nq.append(u) q = nq return x, rd class Graph(BaseGraph): def __init__(self, n_vertices: int, adj: List[int], ind: List[int]): super().__init__(n_vertices) self._adj = adj self._ind = ind @classmethod def from_lil_adj(cls, n_vertices: int, adj_list: Iterable[Sequence[int]]) -> 'Graph': n_edges = sum(len(l) for l in adj_list) adj = [0] * n_edges ind = [0] * (n_vertices + 1) i = 0 for u, l in enumerate(adj_list): ind[u] = i for v in l: adj[i] = v i += 1 ind[n_vertices] = i return cls(n_vertices, adj, ind) @classmethod def from_directed_edges(cls, n_vertices: int, edges: Iterable[Tuple[int, int]]) -> 'Graph': temp = [[] for _ in range(n_vertices)] for u, v in edges: temp[u].append(v) return cls.from_lil_adj(n_vertices, temp) @classmethod def from_undirected_edges(cls, n_vertices: int, edges: Iterable[Tuple[int, int]]) -> 'Graph': temp = [[] for _ in range(n_vertices)] for u, v in edges: temp[u].append(v) temp[v].append(u) return cls.from_lil_adj(n_vertices, temp) def adj(self, v): return self._adj[self._ind[v]: self._ind[v + 1]] class ModifiableGraph(BaseGraph): def __init__(self, n_vertices: int, adj: List[MutableSet[int]]): super().__init__(n_vertices) self._adj = adj @classmethod def from_directed_edges(cls, n_vertices: int, edges: Iterable[Tuple[int, int]]) -> 'ModifiableGraph': temp = [set() for _ in range(n_vertices)] for u, v in edges: temp[u].add(v) return cls(n_vertices, temp) @classmethod def from_undirected_edges(cls, n_vertices: int, edges: Iterable[Tuple[int, int]]) -> 'ModifiableGraph': return cls.from_directed_edges(n_vertices, itertools.chain(edges, ((u, v) for v, u in edges))) def adj(self, v: int) -> Iterable[int]: return self._adj[v] def add_edge(self, v: int, u: int) -> None: self._adj[v].add(u) def delete_edge(self, v: int, u: int) -> None: self._adj[v].discard(u) class Grid(BaseGraph): def __init__(self, grid): super().__init__(grid.n * grid.m) self.grid = grid def adj(self, v): if not self.grid.arr[v]: return i, j = divmod(v, self.grid.m) if i + 1 < self.grid.n and self.grid[i + 1, j]: yield v + self.grid.m if 0 <= i - 1 and self.grid[i - 1, j]: yield v - self.grid.m if j + 1 < self.grid.m and self.grid[i, j + 1]: yield v + 1 if 0 <= j - 1 and self.grid[i, j - 1]: yield v - 1 def strongly_connected_components(graph: BaseWeightedGraph, rgraph: BaseWeightedGraph = None): if rgraph is None: rgraph = graph.to_reverse_graph() n = graph.n_vertices order = [] color = [0] * n for v0 in range(n): if color[v0]: continue color[v0] = -1 stack = [iter(graph.adj(v0))] path = [v0] while path: for u in stack[-1]: if color[u] == 0: color[u] = -1 path.append(u) stack.append(iter(graph.adj(u))) break else: v = path.pop() order.append(v) stack.pop() label = 0 for v0 in reversed(order): if color[v0] >= 0: continue color[v0] = label stack = [v0] while stack: v = stack.pop() for u in rgraph.adj(v): if color[u] < 0: color[u] = label stack.append(u) label += 1 return label, color def bfs(graph: BaseWeightedGraph, s: Union[int, Iterable[int]], t: Union[int, Iterable[int]] = -1) -> List[int]: """ 幅優先探索を行い距離リストを返す。 :param graph: グラフ :param s: 始点集合 :param t: 終点集合 :return: 距離リスト(sから到達不能な頂点は-1) """ dist = [-1] * graph.n_vertices if isinstance(s, int): q = [s] dist[s] = 0 else: q = list(s) for v in q: dist[v] = 0 if isinstance(t, int): t = [t] else: t = list(t) if len(t) > 8: t = set(t) for d in range(1, graph.n_vertices): nq = [] for v in q: for u in graph.adj(v): if dist[u] < 0: dist[u] = d nq.append(u) if u in t: return dist q = nq return dist def dijkstra(graph: BaseWeightedGraph, s: Union[int, Iterable[int]], t: Union[int, Iterable[int]] = -1, inf: int = INF) -> List[int]: """ Returns a list of distance. If starts contains more than one vertex, returns the shortest distance from any of them. """ K = graph.n_vertices.bit_length() MASK = (1 << K) - 1 dist = [inf] * graph.n_vertices if isinstance(s, int): q = [s] dist[s] = 0 else: q = list(s) for v in q: dist[v] = 0 if isinstance(t, int): if t < 0: t = [] else: t = [t] else: t = set(t) while q: x = hq.heappop(q) d, v = x >> K, x & MASK if v in t: return dist if d > dist[v]: continue for u, w in graph.wadj(v): if dist[u] > d + w: dist[u] = d + w hq.heappush(q, ((d + w) << K) | u) return dist import itertools import random class BaseRootedTree(BaseGraph): def __init__(self, n_vertices, root_vertex=0): super().__init__(n_vertices) self.root = root_vertex def parent(self, v: int) -> int: raise NotImplementedError def children(self, v: int) -> Iterable[int]: raise NotImplementedError def adj(self, v) -> Iterable[int]: if self.root == v: return self.children(v) return itertools.chain(self.children(v), (self.parent(v),)) def post_order(self) -> Iterable[int]: """ bottom vertices first """ return (~v for v in self.prepost_order() if v < 0) def pre_order(self) -> Iterable[int]: """ top vertices first """ stack = [self.root] while stack: v = stack.pop() yield v for u in self.children(v): stack.append(u) def prepost_order(self) -> Iterable[int]: """ if v >= 0: it's pre-order entry. otherwise: it's post-order entry. """ stack = [~self.root, self.root] while stack: v = stack.pop() yield v if v >= 0: for u in self.children(v): stack.append(~u) stack.append(u) def prepost_indices(self, order=None) -> Tuple[List[int], List[int]]: if order is None: order = self.prepost_order() pre_ind = [0] * self.n_vertices post_ind = [0] * self.n_vertices for i, t in enumerate(order): if t >= 0: pre_ind[t] = i else: post_ind[~t] = i return pre_ind, post_ind def depth(self) -> List[int]: depth = [0] * self.n_vertices for v in self.pre_order(): d = depth[v] for c in self.children(v): depth[c] = d + 1 return depth def sort_edge_values(self, wedges: Iterable[Tuple[int, int, T]], default: Optional[T] = None) -> List[T]: memo = [default] * self.n_vertices for u, v, d in wedges: if self.parent(u) == v: memo[u] = d else: memo[v] = d return memo def height(self, depth_list: Optional[List[int]] = None) -> int: if depth_list is None: depth_list = self.depth() return max(depth_list) + 1 def path_to_ancestor(self, v: int, k: int) -> List[int]: """ 頂点vからk頂点上までの経路を返す. :param v: 頂点 :param k: 何個上の親まで遡るか :return: 経路 """ res = [-1] * (k + 1) for i in range(k + 1): res[i] = v v = self.parent(v) if v < 0: break return res def path(self, s: int, t: int, depth_list: Optional[List[int]] = None) -> List[int]: """ 頂点sから頂点tまでの経路を返す。 :param s: 始点 :param t: 終点 :param depth_list: 頂点の深さのリスト (optional) :return: 経路 """ if s == t: return [s] if depth_list: d1 = depth_list[s] d2 = depth_list[t] else: d1 = 0 v = s while v >= 0: v = self.parent(v) d1 += 1 d2 = 0 v = t while v >= 0: v = self.parent(v) d2 += 1 p1 = [s] p2 = [t] if d1 > d2: for _ in range(d1 - d2): p1.append(self.parent(p1[-1])) else: for _ in range(d2 - d1): p2.append(self.parent(p2[-1])) while p1[-1] != p2[-1]: p1.append(self.parent(p1[-1])) p2.append(self.parent(p2[-1])) p2.pop() p1.extend(reversed(p2)) return p1 def aggregate_root_path(self, aggregate: Callable[[T, int], T], identity: T, pre_order: Optional[Iterable[int]] = None) -> List[T]: """ 根から頂点までの経路上のdp和を計算する. :param aggregate: (T, V) -> T :param identity: 単位元 :param pre_order: pre_orderの頂点列 :return 根からそれぞれの頂点までのdp和 """ if pre_order is None: pre_order = self.pre_order() dp = [identity] * self.n_vertices for v in pre_order: p = self.parent(v) if p >= 0: dp[v] = aggregate(dp[p], v) return dp def aggregate_subtree(self, merge: Callable[[int, Callable[[None], Iterator[T]]], T], post_order: Optional[Iterable[int]] = None) -> List[T]: """ それぞれの下方向部分木についてdp和を計算する. :param merge: (vertex, Iterable(T)) -> T, (T, merge)はモノイド :param post_order: post_orderの頂点列 :return それぞれの頂点を根とする下方向部分木のdp和 """ if post_order is None: post_order = self.post_order() dp = [None] * self.n_vertices for v in post_order: dp[v] = merge(v, lambda: (dp[u] for u in self.children(v))) return dp def solve_rerooting(self, merge: Callable[[T, T, int], T], identity: T, finalize: Callable[[T, int, int], T], pre_order: Optional[Iterable[int]] = None) -> List[T]: """ 全方位木dpを解く。 dp[u,v] = finalize(merge(dp[v,k] for k in adj[v] if k != u, v), u, v) (vを根とするuを含まないような部分木についての解) :param merge: (T, T, V) -> T, (T, merge)はモノイド :param identity: 単位元 :param finalize: (T, V, V) -> T :param pre_order: pre_orderの頂点列 :return それぞれの頂点を根としたときのdp解 """ if pre_order is None: pre_order = list(self.pre_order()) dp1 = [identity] * self.n_vertices dp2 = [identity] * self.n_vertices for v in reversed(pre_order): t = identity for u in self.children(v): dp2[u] = t t = merge(t, finalize(dp1[u], v, u), v) t = identity for u in reversed(list(self.children(v))): dp2[u] = merge(t, dp2[u], v) t = merge(t, finalize(dp1[u], v, u), v) dp1[v] = t for v in pre_order: if v == self.root: continue p = self.parent(v) dp2[v] = finalize(merge(dp2[v], dp2[p], v), v, p) dp1[v] = merge(dp1[v], dp2[v], v) return dp1 def subtree_sizes(self, post_order: Optional[Iterable[int]] = None): def merge(v, values): return sum(values)+1 return self.aggregate_subtree(merge, post_order) class RootedTree(BaseRootedTree): def __init__(self, parent: List[int], children: Graph, root_vertex: int): super().__init__(len(parent), root_vertex) self._parent = parent self._children = children @classmethod def from_edges(cls, edges, root_vertex=0): n = len(edges) + 1 g = Graph.from_undirected_edges(n, edges) parent = [0] * n parent[root_vertex] = -1 stack = [root_vertex] while stack: v = stack.pop() p = parent[v] for u in g.adj(v): if u != p: parent[u] = v stack.append(u) return cls.from_parent(parent, root_vertex) @classmethod def from_parent(cls, parent, root_vertex=0): return cls(parent, Graph.from_directed_edges(len(parent), ((p, v) for v, p in enumerate(parent) if p >= 0)), root_vertex) @classmethod def random(cls, n_vertices, root_vertex=0): parent = [-1] * n_vertices vertices = list(range(root_vertex)) + list(range(root_vertex + 1, n_vertices)) random.shuffle(vertices) vertices.append(root_vertex) for i, v in zip(reversed(range(n_vertices)), vertices[-2::-1]): parent[v] = vertices[random.randrange(i, n_vertices)] return cls.from_parent(parent, root_vertex) def parent(self, v): return self._parent[v] def children(self, v): return self._children.adj(v) def helper(tree: RootedTree): def merge(x, y, v): tx, rx, cx = x ty, ry, cy = y return (tx+ty+cy*rx+cx*ry), rx+ry, cx+cy def finalize(x, u, v): t,r,c = x c += 1 if u < 0: return t+r, r, c else: return t+r, r+c, c dp = tree.solve_rerooting(merge, (0, 0, 0), finalize) return [finalize(x, -1, -1) for x in dp] def solve(ep, wp, queries): ep.append(-1) wp.append(-1) et = RootedTree.from_parent(ep, root_vertex=len(ep)-1) wt = RootedTree.from_parent(wp, root_vertex=len(wp)-1) dp0 = helper(et) dp1 = helper(wt) res = [] n = len(ep)+len(wp) total = n*(n-1)//2 alpha = len(ep)*len(wp) for ei,wi in queries: t0, r0, c0 = dp0[ei] t1, r1, c1 = dp1[wi] cost = t0+t1 + r0*c1 + r1*c0 + alpha res.append(cost/total) return res tests = int(input()) for ti in range(tests): w,e,c = map(int,input().split()) ep = [int(c)-1 for c in input().split()] wp = [int(c)-1 for c in input().split()] queries = [tuple(int(c)-1 for c in input().split()) for _ in range(c)] print(f'Case #{ti+1}:', *solve(ep, wp, queries))