結果
問題 | No.2316 Freight Train |
ユーザー |
|
提出日時 | 2023-05-26 22:05:26 |
言語 | Python3 (3.13.1 + numpy 2.2.1 + scipy 1.14.1) |
結果 |
AC
|
実行時間 | 893 ms / 2,000 ms |
コード長 | 29,137 bytes |
コンパイル時間 | 450 ms |
コンパイル使用メモリ | 15,232 KB |
実行使用メモリ | 35,732 KB |
最終ジャッジ日時 | 2024-12-25 07:07:26 |
合計ジャッジ時間 | 21,178 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 26 |
ソースコード
import timefrom typing import Generic, Iterable, Iterator, TypeVar, Optional, Listfrom array import arrayfrom bisect import bisect_left, bisect_right, insortimport collectionsimport copyimport heapqimport itertoolsimport decimalfrom decimal import Decimalimport mathimport stringimport syssys.setrecursionlimit(10**6)def I(): return int(sys.stdin.readline().rstrip())def MI(): return map(int, sys.stdin.readline().rstrip().split())def LI(): return list(map(int, sys.stdin.readline().rstrip().split()))def LII(H): return [list(map(int, sys.stdin.readline().rstrip().split())) for _ in range(H)]def S(): return sys.stdin.readline().rstrip()def SS(H): return [S() for _ in range(H)]def LS(): return list(sys.stdin.readline().rstrip().split())def ARRAY(L): return array("i", L)INF = 1 << 61DIFF = 10 ** -9DX = [1, 0, -1, 0, 1, 1, -1, -1]DY = [0, 1, 0, -1, 1, -1, 1, -1]MOD = 998244353# 累積和 ans=list(itertools.accumulate(L))# 順列 ans=list(itertools.permutation(L))# 直積 ans=list(itertools.product(L,M))# 重複なし組み合わせ ans=list(itertools.combinations(L,2))# 重複あり組み合わせ ans=list(itertools.combinations_with_replacement(L,2))# nCr ans=math.comb(n,r)# 日付を比較def compare_date(date1, date2):# date = "2019/04/30"formatted_date1 = time.strptime(date1, "%Y/%m/%d")formatted_date2 = time.strptime(date2, "%Y/%m/%d")return formatted_date1 < formatted_date2# 四捨五入def half_up(x):return Decimal(x).quantize(Decimal('1'), rounding=decimal.ROUND_HALF_UP)# 切り上げdef ceiling(x):return Decimal(x).quantize(Decimal('0.1'), rounding=decimal.ROUND_CEILING)# 切り捨てdef floor(x):return Decimal(x).quantize(Decimal('0.1'), rounding=decimal.ROUND_FLOOR)# Nまでの数を素数かどうか判定(エラトステネスのふるい)def prime_list(n: int):is_prime = [True] * (n + 1)is_prime[0], is_prime[1] = False, Falsefor i in range(2, int(math.sqrt(n)) + 1):if is_prime[i]:for j in range(2 * i, n + 1, i):is_prime[j] = Falsereturn is_prime# 素因数分解def prime_factorization(N: int):arr = []sqrt = int(math.sqrt(N))for i in range(2, sqrt+1):if N % i == 0:cnt = 0while N % i == 0:cnt += 1N //= iarr.append([i, cnt])if N != 1:arr.append([N, 1])return arr# 1文字ずつ文字列をずらしたときの最長共通接頭辞の長さdef z_algorithm(S: string):n = len(S)rtn = [-1]*nrtn[0] = ni, j = 1, 0while i < len(S):while i+j < len(S) and S[j] == S[i+j]:j += 1rtn[i] = jif j == 0:i += 1k = 1while i+k < len(S) and k+rtn[k] < j:rtn[i+k] = rtn[k]k += 1i += kj -= kreturn rtn# Nまでの積をxで何回割り切れるかdef divide_num(N: int, x: int):rtn = 0i = 1while pow(x, i) <= N:rtn += N//pow(x, i)i += 1return rtn# 拡張ユークリッド互除法def xgcd(a, b):x0, y0, x1, y1 = 1, 0, 0, 1while b != 0:q, a, b = a//b, b, a % bx0, x1 = x1, x0-q*x1y0, y1 = y1, y0-q*y1return a, x0, y0# 逆元を求めるdef modinv(a, mod=MOD):g, x, y = xgcd(a, mod)if g != 1:raise Exception("moduler inverse does not exist")else:return x % mod# combinationの逆元を求めるdef combination_modinv(n, r, mod=MOD):if n < 0 or r < 0 or n < r:return 0fact = [1]*(n+2)fact_inv = [1]*(n+2)for i in range(1, n+2):fact[i] = (fact[i-1]*i) % modfact_inv[n+1] = pow(fact[n+1], mod-2, mod)for i in range(n, -1, -1):fact_inv[i] = (fact_inv[i+1]*(i+1)) % modreturn (fact[n]*fact_inv[r] % mod)*fact_inv[n-r] % modclass BIT:# 長さN+1の配列を初期化def __init__(self, N):self.size = Nself.bit = [0]*(N+1)# i番目までの和を求めるdef sum(self, i):res = 0while i > 0:res += self.bit[i] # フェニック木のi番目の値を加算i -= -i & i # 最も右にある1の桁を0にするreturn res# i番目の値にxを足して更新するdef add(self, i, x):while i <= self.size:self.bit[i] += x # フェニック木のi番目にxを足して更新i += -i & i # 最も右にある1の桁に1を足す# N mod p = a, N mod q = b# px + a = qy + b# px - qy = b-a# px = 1 mod qdef crp(a, p, b, q):x = pow(p, -1, q)x *= b-ax %= qreturn p*x + adef Dijkstra(edges, num_node):""" 経路の表現[終点, 辺の値]A, B, C, D, ... → 0, 1, 2, ...とする """node = [float('inf')] * num_node # スタート地点以外の値は∞で初期化node[0] = 0 # スタートは0で初期化node_name = [i for i in range(num_node)] # ノードの名前を0~ノードの数で表すwhile len(node_name) > 0:r = node_name[0]# 最もコストが小さい頂点を探すfor i in node_name:if node[i] < node[r]:r = i # コストが小さい頂点が見つかると更新# 最もコストが小さい頂点を取り出すmin_point = node_name.pop(node_name.index(r))# 経路の要素を各変数に格納することで,視覚的に見やすくするfor factor in edges[min_point]:goal = factor[0] # 終点cost = factor[1] # コスト# 更新条件if node[min_point] + cost < node[goal]:node[goal] = node[min_point] + cost # 更新return node# 行きがけ、帰りがけの順番を取得def EulerTour(n, graph, root):"""(n: int, graph: List[List[int]], root: int) -> Tuple[List[int], List[int], List[int]]::param n: the number of vertex points:param graph: 2D matrix of N vertices given by the edges:param root: start node index:return tour: order of visited vertex:return in_time: first visiting time of each vertex:return out_time: last visiting time of each vertexexample:graph = [[] for _ in range(n)]for _ in range(n):a, b = map(int, input().split())graph[a].append(b)graph[b].append(a)tour, in_time, out_time = EulerTour(n, graph, 0)"""parent = [-1] * nstack = [~root, root] # postorder, preordercurr_time = -1tour = []in_time = [-1] * nout_time = [-1] * nwhile stack:curr_node = stack.pop()curr_time += 1if curr_node >= 0: # preordertour.append(curr_node)if in_time[curr_node] == -1:in_time[curr_node] = curr_timefor next_node in graph[curr_node]:if next_node != parent[curr_node]:parent[next_node] = curr_nodestack.append(~next_node)stack.append(next_node)elif curr_node < 0: # postorderout_time[~curr_node] = curr_timeif parent[~curr_node] != -1:tour.append(parent[~curr_node])return tour, in_time, out_timeclass UnionFind():def __init__(self, n):self.n = nself.parents = [-1] * ndef find(self, x):if self.parents[x] < 0:return xelse:self.parents[x] = self.find(self.parents[x])return self.parents[x]def union(self, x, y):x = self.find(x)y = self.find(y)if x == y:returnif self.parents[x] > self.parents[y]:x, y = y, xself.parents[x] += self.parents[y]self.parents[y] = xdef size(self, x):return -self.parents[self.find(x)]def same(self, x, y):return self.find(x) == self.find(y)def members(self, x):root = self.find(x)return [i for i in range(self.n) if self.find(i) == root]def roots(self):return [i for i, x in enumerate(self.parents) if x < 0]def group_count(self):return len(self.roots())def all_group_members(self):group_members = collections.defaultdict(list)for member in range(self.n):group_members[self.find(member)].append(member)return group_membersdef __str__(self):return '\n'.join(f'{r}: {m}' for r, m in self.all_group_members().items())def make_kmp_table(t):i = 2j = 0m = len(t)tbl = [0] * (m + 1)tbl[0] = -1while i <= m:if t[i - 1] == t[j]:tbl[i] = j + 1i += 1j += 1elif j > 0:j = tbl[j]else:tbl[i] = 0i += 1return tbl# 文字列Sの中に文字列Tが存在するかどうかdef kmp(s, t):matched_indices = []tbl = make_kmp_table(t)i = 0j = 0n = len(s)m = len(t)while i + j < n:if t[j] == s[i + j]:j += 1if j == m:matched_indices.append(i)i += j - tbl[j]j = tbl[j]else:i += j - tbl[j]if j > 0:j = tbl[j]return matched_indices# 強連結成分分解class SCC:def __init__(self, n):self.n = nself.graph = [[] for _ in range(n)]self.rev_graph = [[] for _ in range(n)]self.labels = [-1] * nself.lb_cnt = 0def add_edge(self, v, nxt_v):self.graph[v].append(nxt_v)self.rev_graph[nxt_v].append(v)def build(self):self.post_order = []self.used = [False] * self.nfor v in range(self.n):if not self.used[v]:self._dfs(v)for v in reversed(self.post_order):if self.labels[v] == -1:self._rev_dfs(v)self.lb_cnt += 1def _dfs(self, v):stack = [v, 0]while stack:v, idx = stack[-2:]if not idx and self.used[v]:stack.pop()stack.pop()else:self.used[v] = Trueif idx < len(self.graph[v]):stack[-1] += 1stack.append(self.graph[v][idx])stack.append(0)else:stack.pop()self.post_order.append(stack.pop())def _rev_dfs(self, v):stack = [v]self.labels[v] = self.lb_cntwhile stack:v = stack.pop()for nxt_v in self.rev_graph[v]:if self.labels[nxt_v] != -1:continuestack.append(nxt_v)self.labels[nxt_v] = self.lb_cntdef construct(self):self.dag = [[] for i in range(self.lb_cnt)]self.groups = [[] for i in range(self.lb_cnt)]for v, lb in enumerate(self.labels):for nxt_v in self.graph[v]:nxt_lb = self.labels[nxt_v]if lb == nxt_lb:continueself.dag[lb].append(nxt_lb)self.groups[lb].append(v)return self.dag, self.groupsclass SegTree:""" 点代入/区間総和操作 segfunc 単位元最小値 min(x, y) float('inf')最大値 max(x, y) -float('inf')区間和 x + y 0区間積 x * y 1最大公約数 math.gcd(x, y) 0segfunc : 和の計算がデフォ、最小値・最大値などのモノイドに置換add : k番目の値にxを加算update : k番目の値をxに更新query : 区間[l,r)のseg_funcモノイドの結果を出力"""def __init__(self, init_val: list, ide_ele: int = 0):n = len(init_val)self.ide_ele = ide_eleself.num = 1 << (n-1).bit_length()self.tree = [ide_ele]*2*self.numfor i in range(n):self.tree[self.num+i] = init_val[i]for i in range(self.num-1, 0, -1):self.tree[i] = self.segfunc(self.tree[2*i], self.tree[2*i+1])def segfunc(x, y):return x+ydef add(self, k, x):k += self.numself.tree[k] += xwhile k > 1:self.tree[k >> 1] = self.segfunc(self.tree[k], self.tree[k ^ 1])k >>= 1def update(self, k, x):k += self.numself.tree[k] = xwhile k > 1:self.tree[k >> 1] = self.segfunc(self.tree[k], self.tree[k ^ 1])k >>= 1def query(self, l, r):res = self.ide_elel += self.numr += self.numwhile l < r:if l & 1:res = self.segfunc(res, self.tree[l])l += 1if r & 1:res = self.segfunc(res, self.tree[r-1])l >>= 1r >>= 1return resclass LazySegTree_RAQ:""" 区間代入/区間総和seg_func : 和の計算がデフォ、最小値・最大値などのモノイドに置換add : 区間[l,r)の値にxを加算query : 区間[l,r)のseg_funcモノイドの結果を出力"""def __init__(self, init_val, segfunc=None, ide_ele: int = 0):n = len(init_val)self.ide_ele = ide_eleif segfunc is not None:self.segfunc = segfuncself.num = 1 << (n-1).bit_length()self.tree = [ide_ele]*2*self.numself.lazy = [0]*2*self.numfor i in range(n):self.tree[self.num+i] = init_val[i]for i in range(self.num-1, 0, -1):self.tree[i] = self.segfunc(self.tree[2*i], self.tree[2*i+1])def segfunc(x, y):return x+ydef gindex(self, l, r):l += self.numr += self.numlm = l >> (l & -l).bit_length()rm = r >> (r & -r).bit_length()while r > l:if l <= lm:yield lif r <= rm:yield rr >>= 1l >>= 1while l:yield ll >>= 1def propagates(self, *ids):for i in reversed(ids):v = self.lazy[i]if v == 0:continueself.lazy[i] = 0self.lazy[2*i] += vself.lazy[2*i+1] += vself.tree[2*i] += vself.tree[2*i+1] += vdef add(self, l, r, x):ids = self.gindex(l, r)l += self.numr += self.numwhile l < r:if l & 1:self.lazy[l] += xself.tree[l] += xl += 1if r & 1:self.lazy[r-1] += xself.tree[r-1] += xr >>= 1l >>= 1for i in ids:self.tree[i] = self.segfunc(self.tree[2*i], self.tree[2*i+1]) + self.lazy[i]def query(self, l, r):self.propagates(*self.gindex(l, r))res = self.ide_elel += self.numr += self.numwhile l < r:if l & 1:res = self.segfunc(res, self.tree[l])l += 1if r & 1:res = self.segfunc(res, self.tree[r-1])l >>= 1r >>= 1return resclass LazySegTree_RUQ:""" 区間代入/区間総和seg_func : 和の計算がデフォ、最小値・最大値などのモノイドに置換update : 区間[l,r)の値をxに加算query : 区間[l,r)のseg_funcモノイドの結果を出力"""def __init__(self, init_val: list, segfunc=None, ide_ele: int = 0):n = len(init_val)self.ide_ele = ide_eleself.num = 1 << (n-1).bit_length()if segfunc is not None:self.segfunc = segfuncself.tree = [ide_ele]*2*self.numself.lazy = [None]*2*self.numfor i in range(n):self.tree[self.num+i] = init_val[i]for i in range(self.num-1, 0, -1):self.tree[i] = self.segfunc(self.tree[2*i], self.tree[2*i+1])def segfunc(x, y):return min(x, y)def gindex(self, l, r):l += self.numr += self.numlm = l >> (l & -l).bit_length()rm = r >> (r & -r).bit_length()while r > l:if l <= lm:yield lif r <= rm:yield rr >>= 1l >>= 1while l:yield ll >>= 1def propagates(self, *ids):for i in reversed(ids):v = self.lazy[i]if v is None:continueself.lazy[i] = Noneself.lazy[2*i] = vself.lazy[2*i+1] = vself.tree[2*i] = vself.tree[2*i+1] = vdef update(self, l, r, x):ids = self.gindex(l, r)self.propagates(*self.gindex(l, r))l += self.numr += self.numwhile l < r:if l & 1:self.lazy[l] = xself.tree[l] = xl += 1if r & 1:self.lazy[r-1] = xself.tree[r-1] = xr >>= 1l >>= 1for i in ids:self.tree[i] = self.segfunc(self.tree[2*i], self.tree[2*i+1])def query(self, l, r):ids = self.gindex(l, r)self.propagates(*self.gindex(l, r))res = self.ide_elel += self.numr += self.numwhile l < r:if l & 1:res = self.segfunc(res, self.tree[l])l += 1if r & 1:res = self.segfunc(res, self.tree[r-1])l >>= 1r >>= 1return resT = TypeVar('T')class SortedSet(Generic[T]):BUCKET_RATIO = 50REBUILD_RATIO = 170def _build(self, a=None) -> None:"Evenly divide `a` into buckets."if a is None:a = list(self)size = self.size = len(a)bucket_size = int(math.ceil(math.sqrt(size / self.BUCKET_RATIO)))self.a = [a[size * i // bucket_size: size * (i + 1) // bucket_size] for i in range(bucket_size)]def __init__(self, a: Iterable[T] = []) -> None:"Make a new SortedSet from iterable. / O(N) if sorted and unique / O(N log N)"a = list(a)if not all(a[i] < a[i + 1] for i in range(len(a) - 1)):a = sorted(set(a))self._build(a)def __iter__(self) -> Iterator[T]:for i in self.a:for j in i:yield jdef __reversed__(self) -> Iterator[T]:for i in reversed(self.a):for j in reversed(i):yield jdef __len__(self) -> int:return self.sizedef __repr__(self) -> str:return "SortedSet" + str(self.a)def __str__(self) -> str:s = str(list(self))return "{" + s[1: len(s) - 1] + "}"def _find_bucket(self, x: T) -> List[T]:"Find the bucket which should contain x. self must not be empty."for a in self.a:if x <= a[-1]:return areturn adef __contains__(self, x: T) -> bool:if self.size == 0:return Falsea = self._find_bucket(x)i = bisect_left(a, x)return i != len(a) and a[i] == xdef add(self, x: T) -> bool:"Add an element and return True if added. / O(√N)"if self.size == 0:self.a = [[x]]self.size = 1return Truea = self._find_bucket(x)i = bisect_left(a, x)if i != len(a) and a[i] == x:return Falsea.insert(i, x)self.size += 1if len(a) > len(self.a) * self.REBUILD_RATIO:self._build()return Truedef discard(self, x: T) -> bool:"Remove an element and return True if removed. / O(√N)"if self.size == 0:return Falsea = self._find_bucket(x)i = bisect_left(a, x)if i == len(a) or a[i] != x:return Falsea.pop(i)self.size -= 1if len(a) == 0:self._build()return Truedef lt(self, x: T) -> Optional[T]:"Find the largest element < x, or None if it doesn't exist."for a in reversed(self.a):if a[0] < x:return a[bisect_left(a, x) - 1]def le(self, x: T) -> Optional[T]:"Find the largest element <= x, or None if it doesn't exist."for a in reversed(self.a):if a[0] <= x:return a[bisect_right(a, x) - 1]def gt(self, x: T) -> Optional[T]:"Find the smallest element > x, or None if it doesn't exist."for a in self.a:if a[-1] > x:return a[bisect_right(a, x)]def ge(self, x: T) -> Optional[T]:"Find the smallest element >= x, or None if it doesn't exist."for a in self.a:if a[-1] >= x:return a[bisect_left(a, x)]def __getitem__(self, x: int) -> T:"Return the x-th element, or IndexError if it doesn't exist."if x < 0:x += self.sizeif x < 0:raise IndexErrorfor a in self.a:if x < len(a):return a[x]x -= len(a)raise IndexErrordef index(self, x: T) -> int:"Count the number of elements < x."ans = 0for a in self.a:if a[-1] >= x:return ans + bisect_left(a, x)ans += len(a)return ansdef index_right(self, x: T) -> int:"Count the number of elements <= x."ans = 0for a in self.a:if a[-1] > x:return ans + bisect_right(a, x)ans += len(a)return ansclass SortedMultiset(Generic[T]):BUCKET_RATIO = 50REBUILD_RATIO = 170def _build(self, a=None) -> None:"Evenly divide `a` into buckets."if a is None:a = list(self)size = self.size = len(a)bucket_size = int(math.ceil(math.sqrt(size / self.BUCKET_RATIO)))self.a = [a[size * i // bucket_size: size * (i + 1) // bucket_size] for i in range(bucket_size)]def __init__(self, a: Iterable[T] = []) -> None:"Make a new SortedMultiset from iterable. / O(N) if sorted / O(N log N)"a = list(a)if not all(a[i] <= a[i + 1] for i in range(len(a) - 1)):a = sorted(a)self._build(a)def __iter__(self) -> Iterator[T]:for i in self.a:for j in i:yield jdef __reversed__(self) -> Iterator[T]:for i in reversed(self.a):for j in reversed(i):yield jdef __len__(self) -> int:return self.sizedef __repr__(self) -> str:return "SortedMultiset" + str(self.a)def __str__(self) -> str:s = str(list(self))return "{" + s[1: len(s) - 1] + "}"def _find_bucket(self, x: T) -> List[T]:"Find the bucket which should contain x. self must not be empty."for a in self.a:if x <= a[-1]:return areturn adef __contains__(self, x: T) -> bool:if self.size == 0:return Falsea = self._find_bucket(x)i = bisect_left(a, x)return i != len(a) and a[i] == xdef count(self, x: T) -> int:"Count the number of x."return self.index_right(x) - self.index(x)def add(self, x: T) -> None:"Add an element. / O(√N)"if self.size == 0:self.a = [[x]]self.size = 1returna = self._find_bucket(x)insort(a, x)self.size += 1if len(a) > len(self.a) * self.REBUILD_RATIO:self._build()def discard(self, x: T) -> bool:"Remove an element and return True if removed. / O(√N)"if self.size == 0:return Falsea = self._find_bucket(x)i = bisect_left(a, x)if i == len(a) or a[i] != x:return Falsea.pop(i)self.size -= 1if len(a) == 0:self._build()return Truedef lt(self, x: T) -> Optional[T]:"Find the largest element < x, or None if it doesn't exist."for a in reversed(self.a):if a[0] < x:return a[bisect_left(a, x) - 1]def le(self, x: T) -> Optional[T]:"Find the largest element <= x, or None if it doesn't exist."for a in reversed(self.a):if a[0] <= x:return a[bisect_right(a, x) - 1]def gt(self, x: T) -> Optional[T]:"Find the smallest element > x, or None if it doesn't exist."for a in self.a:if a[-1] > x:return a[bisect_right(a, x)]def ge(self, x: T) -> Optional[T]:"Find the smallest element >= x, or None if it doesn't exist."for a in self.a:if a[-1] >= x:return a[bisect_left(a, x)]def __getitem__(self, x: int) -> T:"Return the x-th element, or IndexError if it doesn't exist."if x < 0:x += self.sizeif x < 0:raise IndexErrorfor a in self.a:if x < len(a):return a[x]x -= len(a)raise IndexErrordef index(self, x: T) -> int:"Count the number of elements < x."ans = 0for a in self.a:if a[-1] >= x:return ans + bisect_left(a, x)ans += len(a)return ansdef index_right(self, x: T) -> int:"Count the number of elements <= x."ans = 0for a in self.a:if a[-1] > x:return ans + bisect_right(a, x)ans += len(a)return ans# 配列の転倒数を求める(o(NlogN))def inversion_num(L: list):max_N = max(L)bit = BIT(max_N)cnt = 0for i, l in enumerate(L):cnt += i-bit.sum(l)bit.add(l, 1)return cnt# 約数列挙def make_divisors(n):lower_divisors, upper_divisors = [], []i = 1while i*i <= n:if n % i == 0:lower_divisors.append(i)if i != n // i:upper_divisors.append(n//i)i += 1return lower_divisors + upper_divisors[::-1]# Nまでの素数列挙# 計算量 O(logN)def prime_list(N):H = [False] * (N + 1)primes = []for i in range(2, N + 1):if H[i]:continueprimes.append(i)for j in range(i, N + 1, i):H[j] = Truereturn primesclass ModInt:def __init__(self, x, mod=998244353):self.x = x % modself.mod = moddef __str__(self):return str(self.x)__repr__ = __str__def __add__(self, other):return (ModInt(self.x + other.x) if isinstance(other, ModInt) elseModInt(self.x + other))def __sub__(self, other):return (ModInt(self.x - other.x) if isinstance(other, ModInt) elseModInt(self.x - other))def __mul__(self, other):return (ModInt(self.x*other.x) if isinstance(other, ModInt) elseModInt(self.x*other))def __truediv__(self, other):return (ModInt(self.x*pow(other.x, self.mod-2, self.mod)) if isinstance(other, ModInt) elseModInt(self.x*pow(other, self.mod-2, self.mod)))def __pow__(self, other):return (ModInt(pow(self.x, other.x, self.mod)) if isinstance(other, ModInt) elseModInt(pow(self.x, other, self.mod)))__radd__ = __add__def __rsub__(self, other):return (ModInt(other.x-self.x) if isinstance(other, ModInt) elseModInt(other-self.x))__rmul__ = __mul__def __rtruediv__(self, other):return (ModInt(other.x * pow(self.x, self.mod-2, self.mod)) if isinstance(other, ModInt) elseModInt(other * pow(self.x, self.mod-2, self.mod)))def __rpow__(self, other):return (ModInt(pow(other.x, self.x, self.mod)) if isinstance(other, ModInt) elseModInt(pow(other, self.x, self.mod)))def main():N, Q = MI()P = LI()uf = UnionFind(N+1)for i, p in enumerate(P, 1):if p == -1:continueuf.union(i, p)ans = []for _ in range(Q):A, B = MI()ans.append("Yes" if uf.same(A, B) else "No")print(*ans, sep="\n")if __name__ == "__main__":main()