< detteiuuさんのAI生成コード置き場

Pythonライブラリ

投稿者detteiuu
言語PyPy3
更新日時 (JST)2026-10-17 19:32:56
サイズ207,400 Byte
参照URL

日時はサーバーが記録したものです。更新すると更新日時が変わるので、不都合がある場合は新しく投稿してください。

テキストで開く
・再帰
import sys
sys.setrecursionlimit(10**6)
import pypyjit
pypyjit.set_param('max_unroll_recursion=-1')

デコレータ
from types import GeneratorType

def bootstrap(f, stack=[]):
    def wrappedfunc(*args, **kwargs):
        if stack:
            return f(*args, **kwargs)
        to = f(*args, **kwargs)
        while True:
            if type(to) is GeneratorType:
                stack.append(to)
                to = next(to)
            else:
                stack.pop()
                if not stack:
                    break
                to = stack[-1].send(to)
        return to
    return wrappedfunc
〇使い方
1. @bootstrap を再帰関数の前につける
2. returnはyieldと書く
3. 自身を呼び出す場合は先頭にyieldと書く(計算式の中などで呼び出す場合は括弧で囲む [(yield func(a))])
4. 戻り値がない場合でも、最後にyieldと書く
5. 再帰上限の変更は書く必要がない

・実行速度の計測
import time
start = time.time()
end = time.time()
print(end - start)

・UnionFind
class UnionFind:
    def __init__(self,n):
        self.n = n
        self.parent_size = [-1]*n
 
    def leader(self,a):
        if self.parent_size[a] < 0:
            return a
        self.parent_size[a] = self.leader(self.parent_size[a])
        return self.parent_size[a]
 
    def merge(self,a,b):
        x, y = self.leader(a), self.leader(b)
        if x == y:
            return 
        if abs(self.parent_size[x]) < abs(self.parent_size[y]):
            x, y = y, x
        self.parent_size[x] += self.parent_size[y]
        self.parent_size[y] = x
        return 
 
    def same(self,a,b):
        return self.leader(a) == self.leader(b)
 
    def size(self,a):
        return abs(self.parent_size[self.leader(a)])
 
    def groups(self):
        result = [[] for _ in range(self.n)]
        for i in range(self.n):
            result[self.leader(i)].append(i)
        return [r for r in result if r != []]

・素数判定
def isPrime(n):
    if n <= 1:
        return False
    else:
        i = 2
        while i**2 <= n:
            if n%i == 0:
                return False
            i += 1
        return True

・エラトステネスのふるい
def eratosthenes(n):
    sieve = [True] * (n + 1)
    for i in range(int(n**0.5) + 1):
        if i < 2:
            sieve[i] = False
        elif sieve[i]:
            for j in range(i, n//i + 1):
                sieve[i * j] = False
    ans = []
    for i in range(n+1):
        if sieve[i]:
            ans.append(i)
    return ans

・10進数→n進数
def base_n(num_10,n):
    str_n = ''
    while num_10:
        if num_10%n>=10:
            return -1
        str_n += str(num_10%n)
        num_10 //= n
    return int(str_n[::-1])

・ユークリッドの互除法
def gcd(a, b):
    r = a % b
    while r != 0:
        a, b = b, r
        r = a % b
    return b

・素因数分解
from math import isqrt

def factorization(n):
    arr = []
    temp = n
    for i in range(2, isqrt(n)+1):
        if temp%i == 0:
            cnt = 0
            while temp%i == 0:
                cnt += 1
                temp //= i
            arr.append([i, cnt])
    if temp != 1:
        arr.append([temp, 1])
    if arr == []:
        arr.append([n, 1])
    return arr

・約数列挙
def divisor(n):
    ans = []
    for i in range(1, int(n**0.5)+1):
        if n % i == 0:
            ans.append(i)
            if i*i != n:
                ans.append(n//i)
    return ans

・2点間の距離
def distance(x1, y1, x2, y2):
    return ((x2-x1)**2 + (y2-y1)**2) ** 0.5
(比較演算をする場合はルートを外してかわりに反対側を2乗する)

・トリミング
def trimming(A):
    minH = len(A)
    maxH = 0
    minW = len(A[0])
    maxW = 0
    for i in range(len(A)):
        for j in range(len(A[0])):
            if A[i][j] == "#":
                minH = min(i, minH)
                maxH = max(i, maxH)
                minW = min(j, minW)
                maxW = max(j, maxW)
    a = []
    for i in range(minH, maxH+1):
        a.append(A[i][minW:maxW+1])
    return a

・回転(時計回り)
def rotateR(A):
    return list(map(list, zip(*A[::-1])))

・回転(反時計回り)
def rotateL(A):
    return list(map(list, zip(*A)))[::-1]

・ランダムアクセスがO(1)のdeque
class Deque:
    def __init__(self, src_arr=[], max_size=300000):
        self.N = max(max_size, len(src_arr)) + 1
        self.buf = list(src_arr) + [None] * (self.N - len(src_arr))
        self.head = 0
        self.tail = len(src_arr)
    def __index(self, i):
        l = len(self)
        if not -l <= i < l: raise IndexError('index out of range: ' + str(i))
        if i < 0:
            i += l
        return (self.head + i) % self.N
    def __extend(self):
        ex = self.N - 1
        self.buf[self.tail+1 : self.tail+1] = [None] * ex
        self.N = len(self.buf)
        if self.head > 0:
            self.head += ex
    def is_full(self):
        return len(self) >= self.N - 1
    def is_empty(self):
        return len(self) == 0
    def append(self, x):
        if self.is_full(): self.__extend()
        self.buf[self.tail] = x
        self.tail += 1
        self.tail %= self.N
    def appendleft(self, x):
        if self.is_full(): self.__extend()
        self.buf[(self.head - 1) % self.N] = x
        self.head -= 1
        self.head %= self.N
    def pop(self):
        if self.is_empty(): raise IndexError('pop() when buffer is empty')
        ret = self.buf[(self.tail - 1) % self.N]
        self.tail -= 1
        self.tail %= self.N
        return ret
    def popleft(self):
        if self.is_empty(): raise IndexError('popleft() when buffer is empty')
        ret = self.buf[self.head]
        self.head += 1
        self.head %= self.N
        return ret
    def __len__(self):
        return (self.tail - self.head) % self.N
    def __getitem__(self, key):
        return self.buf[self.__index(key)]
    def __setitem__(self, key, value):
        self.buf[self.__index(key)] = value
    def __str__(self):
        return 'Deque({0})'.format(str(list(self)))

・セグメント木
def op(x, y):
    return 
class SegTree:
    def __init__(self, init_val, op, ide_ele):
        n = len(init_val)
        self.n = n
        self.op = op
        self.ide_ele = ide_ele
        self.num = 1 << (n - 1).bit_length()
        self.tree = [ide_ele] * 2 * self.num
        for 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.op(self.tree[2 * i], self.tree[2 * i + 1])

    def update(self, k, x):
        k += self.num
        self.tree[k] = x
        while k > 1:
            l, r = k, k^1
            if l > r:
                l, r = r, l
            self.tree[k >> 1] = self.op(self.tree[l], self.tree[r])
            k >>= 1

    def query(self, l, r):
        res_l = self.ide_ele
        res_r = self.ide_ele

        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                res_l = self.op(res_l, self.tree[l])
                l += 1
            if r & 1:
                res_r = self.op(self.tree[r - 1], res_r)
            l >>= 1
            r >>= 1
        return self.op(res_l, res_r)

    def __getitem__(self, n):
        return self.tree[self.num+n]
    
    def List(self):
        return self.tree[self.num:self.num+self.n]
    
    def max_right(self, l, f, limit):
        if l == self.n:
            return self.n
        l += self.num
        sm = self.ide_ele
        while True:
            while l%2 == 0:
                l >>= 1
            if not f(self.op(sm, self.tree[l]), limit):
                while l < self.num:
                    l <<= 1
                    if f(self.op(sm, self.tree[l]), limit):
                        sm = self.op(sm, self.tree[l])
                        l += 1
                return l-self.num
            sm = self.op(sm, self.tree[l])
            l += 1
            if l & -l == l:
                break
        return self.n
    
    def min_left(self, r, f, limit):
        if r == 0:
            return 0
        r += self.num
        sm = self.ide_ele
        while True:
            r -= 1
            while r > 1 and r%2 == 1:
                r >>= 1
            if not f(self.op(self.tree[r], sm), limit):
                while r < self.num:
                    r = 2*r+1
                    if f(self.op(self.tree[r], sm), limit):
                        sm = self.op(self.tree[r], sm)
                        r -= 1
                return r+1-self.num
            sm = self.op(self.tree[r], sm)
            if r & -r == r:
                break
        return 0
〇使い方
1. 初期化用のリストを用意
2. 区間に行う操作をsegfuncに書き込む
   ・最小値 min(x, y)
   ・最大値 max(x, y)
   ・区間和 x + y
   ・区間積 x * y
   ・最大公約数 math.gcd(x, y)
3. 生成
   seg = SegTree(リスト, segfunc, (単位元))
   ・単位元
     ・最小値 float('inf')
     ・最大値 -float('inf')
     ・区間和 0
     ・区間積 1
     ・最大公約数 0
4. 操作
   0-index
   ・更新
     seg.update(k, x) k番目の要素をxに更新
   ・区間の操作の結果を取得
     seg.query(l, r) l以上r未満の区間から値を取得

・ダイクストラ法
def dijkstra(start):
    INF = 10**18
    dist = [INF]*N
    dist[start] = 0
    visited = [False]*N
    que = [(0, start)]
    while que:
        d, now = heappop(que)
        if visited[now]:
            continue
        visited[now] = True
        for next, weight in G[now]:
            if dist[now]+weight < dist[next]:
                dist[next] = dist[now]+weight
                heappush(que, (dist[next], next))
    return dist

・Ford-Fulkerson
class maxflow_edge:
    def __init__(self, to, cap, rev):
        self.to = to
        self.cap = cap
        self.rev = rev

@bootstrap
def dfs(pos, goal, F, G, visited):
    if pos == goal:
        yield F
    visited[pos] = True
    for e in G[pos]:
        if not visited[e.to] and e.cap > 0:
            flow = yield dfs(e.to, goal, min(F, e.cap), G, visited)
            if flow >= 1:
                e.cap -= flow
                G[e.to][e.rev].cap += flow
                yield flow
    yield 0

def maxflow(s, t, N):
    G = [[] for i in range(N)]
    for a, b, c in edge:
        G[a].append(maxflow_edge(b, c, len(G[b])))
        G[b].append(maxflow_edge(a, 0, len(G[a])-1))
    total_flow = 0
    while True:
        visited = [False]*N
        F = dfs(s, t, INF, G, visited)
        if F > 0:
            total_flow += F
        else:
            break
    return total_flow

・逆元
def inverse(n, d):
    return n * pow(d, -1, MOD) % MOD

・遅延セグメント木
〇区間加算用
def segfunc(x,y):
    return 
class LazySegTree_RAQ:
    def __init__(self,init_val,segfunc,ide_ele):
        n = len(init_val)
        self.segfunc = segfunc
        self.ide_ele = ide_ele
        self.num = 1<<(n-1).bit_length()
        self.tree = [ide_ele]*2*self.num
        self.lazy = [0]*2*self.num
        for 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 gindex(self,l,r):
        l += self.num
        r += self.num
        lm = l>>(l&-l).bit_length()
        rm = r>>(r&-r).bit_length()
        ans = []
        while r>l:
            if l<=lm:
                ans.append(l)
            if r<=rm:
                ans.append(r)
            r >>= 1
            l >>= 1
        while l:
            ans.append(l)
            l >>= 1
        return ans
    def propagates(self,ids):
        for i in reversed(ids):
            v = self.lazy[i]
            if v==0:
                continue
            self.lazy[i] = 0
            self.lazy[2*i] += v
            self.lazy[2*i+1] += v
            self.tree[2*i] += v
            self.tree[2*i+1] += v
    def add(self,l,r,x):
        ids = self.gindex(l,r)
        l += self.num
        r += self.num
        while l<r:
            if l&1:
                self.lazy[l] += x
                self.tree[l] += x
                l += 1
            if r&1:
                self.lazy[r-1] += x
                self.tree[r-1] += x
            r >>= 1
            l >>= 1
        for 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_ele
        l += self.num
        r += self.num
        while l<r:
            if l&1:
                res = self.segfunc(res,self.tree[l])
                l += 1
            if r&1:
                res = self.segfunc(res,self.tree[r-1])
            l >>= 1
            r >>= 1
        return res
〇区間更新用
def segfunc(x,y):
    return 
class LazySegTree_RUQ:
    def __init__(self,init_val,segfunc,ide_ele):
        n = len(init_val)
        self.segfunc = segfunc
        self.ide_ele = ide_ele
        self.num = 1<<(n-1).bit_length()
        self.tree = [ide_ele]*2*self.num
        self.lazy = [None]*2*self.num
        for 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 gindex(self,l,r):
        l += self.num
        r += self.num
        lm = l>>(l&-l).bit_length()
        rm = r>>(r&-r).bit_length()
        ans = []
        while r>l:
            if l<=lm:
                ans.append(l)
            if r<=rm:
                ans.append(r)
            r >>= 1
            l >>= 1
        while l:
            ans.append(l)
            l >>= 1
        return ans
    def propagates(self,ids):
        for i in reversed(ids):
            v = self.lazy[i]
            if v is None:
                continue
            self.lazy[i] = None
            self.lazy[2*i] = v
            self.lazy[2*i+1] = v
            self.tree[2*i] = v
            self.tree[2*i+1] = v
    def update(self,l,r,x):
        ids = self.gindex(l,r)
        self.propagates(ids)
        l += self.num
        r += self.num
        while l<r:
            if l&1:
                self.lazy[l] = x
                self.tree[l] = x
                l += 1
            if r&1:
                self.lazy[r-1] = x
                self.tree[r-1] = x
            r >>= 1
            l >>= 1
        for i in ids:
            self.tree[i] = self.segfunc(self.tree[2*i], self.tree[2*i+1])
    def query(self,l,r):
        self.propagates(self.gindex(l,r))
        res = self.ide_ele
        l += self.num
        r += self.num
        while l<r:
            if l&1:
                res = self.segfunc(res,self.tree[l])
                l += 1
            if r&1:
                res = self.segfunc(res,self.tree[r-1])
            l >>= 1
            r >>= 1
        return res
〇使い方
1. 初期化用のリストを用意
2. 区間に行う操作をsegfuncに書き込む
   ・最小値 min(x, y)
   ・最大値 max(x, y)
   ・区間和 x + y
   ・区間積 x * y
   ・最大公約数 math.gcd(x, y)
3. 生成
   seg = SegTree(リスト, segfunc, (単位元))
   ・単位元
     ・最小値 float('inf')
     ・最大値 -float('inf')
     ・区間和 0
     ・区間積 1
     ・最大公約数 0
4. 操作
   0-index
   ・更新
     seg.add(l, r, x) l以上r未満の区間にxを加算
     seg.update(l, r, x) l以上r未満の区間をxに更新
   ・区間の操作の結果を取得
     seg.query(l, r) l以上r未満の区間から値を取得

・素数リスト
18625498411672028939
93638244515503437017
15508888921625689043
桁最大の素数
1桁⋅⋅⋅7
2桁⋅⋅⋅97
3桁⋅⋅⋅997
4桁⋅⋅⋅9973
5桁⋅⋅⋅99991
6桁⋅⋅⋅999983
7桁⋅⋅⋅9999991
8桁⋅⋅⋅99999989
9桁⋅⋅⋅999999937
10桁⋅⋅⋅9999999967
11桁⋅⋅⋅99999999977
12桁⋅⋅⋅999999999989
13桁⋅⋅⋅9999999999971
14桁⋅⋅⋅99999999999973
15桁⋅⋅⋅999999999999989
16桁⋅⋅⋅9999999999999937
17桁⋅⋅⋅99999999999999997
18桁⋅⋅⋅999999999999999989
19桁⋅⋅⋅9999999999999999961
20桁⋅⋅⋅99999999999999999989
桁最小の素数
1桁⋅⋅⋅2
2桁⋅⋅⋅11
3桁⋅⋅⋅101
4桁⋅⋅⋅1009
5桁⋅⋅⋅10007
6桁⋅⋅⋅100003
7桁⋅⋅⋅1000003
8桁⋅⋅⋅10000019
9桁⋅⋅⋅100000007
10桁⋅⋅⋅1000000007
11桁⋅⋅⋅10000000019
12桁⋅⋅⋅100000000003
13桁⋅⋅⋅1000000000039
14桁⋅⋅⋅10000000000037
15桁⋅⋅⋅100000000000031
16桁⋅⋅⋅1000000000000037
17桁⋅⋅⋅10000000000000061
18桁⋅⋅⋅100000000000000003
19桁⋅⋅⋅1000000000000000003
20桁⋅⋅⋅10000000000000000051

・強連結成分分解
def scc(N,edges):
    M=len(edges)
    start=[0]*(N+1)
    elist=[0]*M
    for e in edges:
        start[e[0]+1]+=1
    for i in range(1,N+1):
        start[i]+=start[i-1]
    counter=start[:]
    for e in edges:
        elist[counter[e[0]]]=e[1]
        counter[e[0]]+=1
    visited=[]
    low=[0]*N
    Ord=[-1]*N
    ids=[0]*N
    NG=[0,0]
    def dfs(v):
        stack=[(v,-1,0),(v,-1,1)]
        while stack:
            v,bef,t=stack.pop()
            if t:
                if bef!=-1 and Ord[v]!=-1:
                    low[bef]=min(low[bef],Ord[v])
                    stack.pop()
                    continue
                low[v]=NG[0]
                Ord[v]=NG[0]
                NG[0]+=1
                visited.append(v)
                for i in range(start[v],start[v+1]):
                    to=elist[i]
                    if Ord[to]==-1:
                        stack.append((to,v,0))
                        stack.append((to,v,1))
                    else:
                        low[v]=min(low[v],Ord[to])
            else:
                if low[v]==Ord[v]:
                    while(True):
                        u=visited.pop()
                        Ord[u]=N
                        ids[u]=NG[1]
                        if u==v:
                            break
                    NG[1]+=1
                low[bef]=min(low[bef],low[v])
    for i in range(N):
        if Ord[i]==-1:
            dfs(i)
    for i in range(N):
        ids[i]=NG[1]-1-ids[i]
    group_num=NG[1]
    counts=[0]*group_num
    for x in ids:
        counts[x]+=1
    groups=[[] for i in range(group_num)]
    for i in range(N):
        groups[ids[i]].append(i)
    return groups

・拡張ユークリッドの互除法
def extended_euclid(a, b):
    if b == 0:
        return (1, 0)
    else:
        xd, yd = extended_euclid(b, a % b)
        return (yd, xd - a // b * yd)

・重み付きUnionFind
class WeightedUnionFind:
    def __init__(self, n):
        self.par = [i for i in range(n)]
        self.rank = [0] * n
        self.weight = [0] * n

    def leader(self, x):
        if self.par[x] == x:
            return x
        else:
            y = self.leader(self.par[x])
            self.weight[x] += self.weight[self.par[x]]
            self.par[x] = y
            return y

    def merge(self, x, y, w):
        rx = self.leader(x)
        ry = self.leader(y)
        if self.rank[rx] < self.rank[ry]:
            self.par[rx] = ry
            self.weight[rx] = w - self.weight[x] + self.weight[y]
        else:
            self.par[ry] = rx
            self.weight[ry] = -w - self.weight[y] + self.weight[x]
            if self.rank[rx] == self.rank[ry]:
                self.rank[rx] += 1

    def same(self, x, y):
        return self.leader(x) == self.leader(y)

    def diff(self, x, y):
        return self.weight[x] - self.weight[y]

・3点が同一線上にあるか
def judge(x1, y1, x2, y2, x3, y3):
    return (x1-x3)*(y2-y3)-(x2-x3)*(y1-y3) == 0

・全方位木dp
def LRset(n):
    for i in range(1, len(G[n])):
        L[n][i] = L[n][i-1]+dp[n][i-1]
    for i in reversed(range(len(G[n])-1)):
        R[n][i] = R[n][i+1]+dp[n][i+1]

L = [[0]*len(G[i]) for i in range(N)]
R = [[0]*len(G[i]) for i in range(N)]
LRset(0)

@bootstrap
def rerooting(n, pre, no):
    visited[n] = True
    preno = 0
    for i in range(len(G[n])):
        if G[n][i] == pre:
            preno = i
            break
    dp[n][preno] = L[pre][no]+R[pre][no]+1
    LRset(n)
    for i in range(len(G[n])):
        if not visited[G[n][i]]:
            yield rerooting(G[n][i], n, i)
    yield

visited = [False]*N
visited[0] = True
for i in range(len(G[0])):
    if not visited[G[0][i]]:
        rerooting(G[0][i], 0, i)

・Z-algorithm
def z_algo(S):
    N = len(S)
    A = [0]*N
    i = 1; j = 0
    A[0] = l = len(S)
    while i < l:
        while i+j < l and S[j] == S[i+j]:
            j += 1
        if not j:
            i += 1
            continue
        A[i] = j
        k = 1
        while l-i > k < j - A[k]:
            A[i+k] = A[k]
            k += 1
        i += k; j -= k
    return A

・ローリングハッシュ
class RollingHash:
    def __init__(self, S, type):
        if type == False:
            a = ord("a")-1
        else:
            a = ord("A")-1
        self.hash = [0]
        for i in range(len(S)):
            self.hash.append((self.hash[-1]*26+(ord(S[i])-a))%MOD)
        self.POW = [1]
        for i in range(len(S)):
            self.POW.append(self.POW[-1]*26%MOD)
    
    def query(self, l, r):
        return (self.hash[r]-self.hash[l]*self.POW[r-l])%MOD

・最小共通祖先
class LCA:
    def __init__(self, G, root=0):
        V = len(G)
        self.bit_length = 1
        while 1<<self.bit_length < V:
            self.bit_length += 1
        self.parent = [[-1]*V for _ in range(self.bit_length)]
        self.depth = [-1]*V
        self.bfs(G, root)
        for i in range(self.bit_length-1):
            for j in range(V):
                if self.parent[i][j] != -1:
                    self.parent[i+1][j] = self.parent[i][self.parent[i][j]]
        
    def bfs(self, G, root):
        self.depth[root] = 0
        que = deque()
        que.append(root)
        while que:
            n = que.popleft()
            for v in G[n]:
                if self.depth[v] == -1:
                    self.depth[v] = self.depth[n]+1
                    self.parent[0][v] = n
                    que.append(v)
    
    def lca(self, a, b):
        if self.depth[a] < self.depth[b]:
            a, b = b, a
        for i in range(self.bit_length):
            if (self.depth[a]-self.depth[b]) & 1<<i:
                a = self.parent[i][a]
        if a == b:
            return a
        for i in reversed(range(self.bit_length)):
            if self.parent[i][a] != self.parent[i][b]:
                a = self.parent[i][a]
                b = self.parent[i][b]
        return self.parent[0][a]
    
    def dist(self, a, b):
        return self.depth[a]+self.depth[b]-self.depth[self.lca(a, b)]*2
    
    def is_ancestor(self, u, v):
        return self.lca(u, v) == u
    
    def kth_ancestor(self, n, k):
        for i in range(self.bit_length):
            if 1<<i & k:
                n = self.parent[i][n]
                if n == -1:
                    break
        return n
    
    def jump(self, u, v):
        if u == v:
            return u
        if self.lca(u, v) == u:
            return self.kth_ancestor(v, self.dist(u, v)-1)
        else:
            return self.parent[0][u]
    
    def jump_k(self, u, v, k):
        d = self.dist(u, v)
        if d <= k:
            return v
        lca = self.lca(u, v)
        if k <= self.depth[u]-self.depth[lca]:
            return self.kth_ancestor(u, k)
        else:
            return self.kth_ancestor(v, d-k)
    
    def on_path(self, u, v, x):
        return self.dist(u, x)+self.dist(x, v) == self.dist(u, v)

    def create_path(self, u, v, x):
        if self.on_path(u, v, x):
            return u, v
        if self.on_path(u, x, v):
            return u, x
        if self.on_path(v, x, u):
            return v, x
        return -1, -1

・HL分解(辺)
class HLDecomposition:
    def __init__(self, N, G, segfunc, ide_ele):
        self.N = N
        self.G = G
        self.segfunc = segfunc
        self.ide_ele = ide_ele
        self.parent = [-1]*N
        self.depth = [0]*N
        self.size = [1]*N
        self.heavy = [-1]*N

        self.visited = [False]*N
        self.build1(0)

        self.top = [0]*N
        self.HLD_G = [0]
        self.visited = [False]*N
        self.build2(0)
        self.HLD_G = self.HLD_G[::-1]

        self.node_w = [0]*N
        self.node = [N-1]*N
        self.make_tree()
    
    def update(self, v, w, weight):
        if self.parent[w] == v:
            v, w = w, v
        elif self.parent[v] != w:
            return False
        self.Tree.update(self.node[v], weight)
    
    def query(self, l, r):
        sml, smr = self.ide_ele, self.ide_ele
        while True:
            li, ri = self.node[l], self.node[r]
            if self.top[l] == self.top[r]:
                if self.depth[l] > self.depth[r]:
                    sml = self.segfunc(sml, self.Tree.query(li, ri))
                else:
                    smr = self.segfunc(self.Tree.query(ri, li), smr)
                return self.segfunc(sml, smr)
            else:
                l_top, r_top = self.top[l], self.top[r]
                if self.depth[l_top] > self.depth[r_top]:
                    sml = self.segfunc(sml, self.Tree.query(li, self.node[l_top]+1))
                    l = self.parent[l_top]
                else:
                    smr = self.segfunc(self.Tree.query(ri, self.node[r_top]+1), smr)
                    r = self.parent[r_top]
    
    @bootstrap
    def build1(self, n):
        self.visited[n] = True
        for v, _ in self.G[n]:
            if not self.visited[v]:
                self.parent[v] = n
                self.depth[v] = self.depth[n]+1
                self.size[n] += yield self.build1(v)
                if self.heavy[n] == -1 or self.size[self.heavy[n]] < self.size[v]:
                    self.heavy[n] = v
        yield self.size[n]
    
    @bootstrap
    def build2(self, n):
        self.visited[n] = True
        if self.heavy[n] != -1:
            v = self.heavy[n]
            self.top[v] = self.top[n]
            self.HLD_G.append(v)
            yield self.build2(v)
        for v, _ in self.G[n]:
            if not self.visited[v] and v != self.heavy[n]:
                self.top[v] = v
                self.HLD_G.append(v)
                yield self.build2(v)
        yield
    
    def make_tree(self):
        for i, n in enumerate(self.HLD_G[:-1]):
            for v, w in self.G[n]:
                if v == self.parent[n]:
                    self.node_w[i] = w
                    break
            self.node[n] = i
        self.Tree = SegTree(self.node_w, self.segfunc, self.ide_ele)

・HL分解(頂点)
class HLDecomposition:
    def __init__(self, N, G, segfunc, ide_ele):
        self.N = N
        self.G = G
        self.segfunc = segfunc
        self.ide_ele = ide_ele
        self.parent = [-1]*N
        self.depth = [0]*N
        self.size = [1]*N
        self.heavy = [-1]*N

        self.visited = [False]*N
        self.build1(0)

        self.top = [0]*N
        self.HLD_G = [0]
        self.visited = [False]*N
        self.build2(0)
        self.HLD_G = self.HLD_G[::-1]

        self.node_w = [0]*N
        self.node = [N-1]*N
        self.make_tree()
    
    def update(self, n, weight):
        self.Tree.update(self.node[n], weight)
    
    def query(self, l, r):
        sml, smr = self.ide_ele, self.ide_ele
        while True:
            li, ri = self.node[l], self.node[r]
            if self.top[l] == self.top[r]:
                if self.depth[l] > self.depth[r]:
                    sml = self.segfunc(sml, self.Tree.query(li, ri+1))
                else:
                    smr = self.segfunc(self.Tree.query(ri, li+1), smr)
                return self.segfunc(sml, smr)
            else:
                l_top, r_top = self.top[l], self.top[r]
                if self.depth[l_top] > self.depth[r_top]:
                    sml = self.segfunc(sml, self.Tree.query(li, self.node[l_top]+1))
                    l = self.parent[l_top]
                else:
                    smr = self.segfunc(self.Tree.query(ri, self.node[r_top]+1), smr)
                    r = self.parent[r_top]
    
    @bootstrap
    def build1(self, n):
        self.visited[n] = True
        for v in self.G[n]:
            if not self.visited[v]:
                self.parent[v] = n
                self.depth[v] = self.depth[n]+1
                self.size[n] += yield self.build1(v)
                if self.heavy[n] == -1 or self.size[self.heavy[n]] < self.size[v]:
                    self.heavy[n] = v
        yield self.size[n]
    
    @bootstrap
    def build2(self, n):
        self.visited[n] = True
        if self.heavy[n] != -1:
            v = self.heavy[n]
            self.top[v] = self.top[n]
            self.HLD_G.append(v)
            yield self.build2(v)
        for v in self.G[n]:
            if not self.visited[v] and v != self.heavy[n]:
                self.top[v] = v
                self.HLD_G.append(v)
                yield self.build2(v)
        yield
    
    def make_tree(self):
        for i, n in enumerate(self.HLD_G):
            self.node_w[i] = A[n]
            self.node[n] = i
        self.Tree = SegTree(self.node_w, self.segfunc, self.ide_ele)

・等比数列
def geometric_progression(a, r, n):
    # a = 初項 r = 公比 n = 項数
    return a*((pow(r, n, MOD)-1)%MOD)%MOD*inverse(1, r-1)%MOD

・ベクトル
def vec(a, b):
    return (b[0]-a[0], b[1]-a[1])

・ベクトルの絶対値
def vec2(a):
    return (a[0]**2+a[1]**2)**0.5

・内積
def inner_product(v1, v2):
    return v1[0]*v2[0]+v1[1]*v2[1]

・外積
def cross_product(v1, v2):
    return v1[0]*v2[1]-v1[1]*v2[0]

・∠BACの角度
def angle(bx, by, ax, ay, cx, cy):
    ab = vec((ax, ay), (bx, by))
    ac = vec((ax, ay), (cx, cy))
    top = ab[0]*ac[0]+ab[1]*ac[1]
    if cross_product(ab, ac) <= 0:
        return degrees(acos(top/(vec2(ab)*vec2(ac))))
    else:
        return 360-degrees(acos(top/(vec2(ab)*vec2(ac))))

・組み合わせの数
class CP:
    def __init__(self, N):
        self.fact = [1]*(N+1)
        self.fact_inv = [1]*(N+1)
        for i in range(2, N+1):
            self.fact[i] = self.fact[i-1]*i%MOD
        self.fact_inv[N] = pow(self.fact[N], -1, MOD)
        for i in reversed(range(1, N)):
            self.fact_inv[i] = self.fact_inv[i+1]*(i+1)%MOD
    def C(self, N, K):
        if N < 0 or K < 0 or N < K:
            return 0
        return self.fact[N]*self.fact_inv[K]%MOD*self.fact_inv[N-K]%MOD
    def P(self, N, K):
        if N < 0 or K < 0 or N < K:
            return 0
        return self.fact[N]*self.fact_inv[N-K]%MOD
    def H(self, N, K):
        if N < 0 or K < 0:
            return 0
        if N == K == 0: return 1
        return self.C(N+K-1, K)

・Dinic
class Dinic_edge:
    def __init__(self, t, cap, rev):
        self.t = t
        self.cap = cap
        self.rev = rev

class Dinic:
    def __init__(self, N):
        self.N = N
        self.G = [[] for _ in range(N)]
    
    def add_edge(self, u, v, cap):
        self.G[u].append(Dinic_edge(v, cap, len(self.G[v])))
        self.G[v].append(Dinic_edge(u, 0, len(self.G[u])-1))
    
    def bfs(self, s, to):
        self.level = [-1]*self.N
        que = deque()
        que.append(s)
        self.level[s] = 0
        while que:
            n = que.popleft()
            for v in self.G[n]:
                if v.cap and self.level[v.t] == -1:
                    self.level[v.t] = self.level[n]+1
                    que.append(v.t)
        return self.level[to] != -1

    @bootstrap
    def dfs(self, n, to, f):
        if n == to:
            yield f
        for v in self.it[n]:
            if v.cap and self.level[n] < self.level[v.t]:
                d = yield self.dfs(v.t, to, min(f, v.cap))
                if d:
                    v.cap -= d
                    self.G[v.t][v.rev].cap += d
                    yield d
        yield 0
    
    def flow(self, s, t):
        flow = 0
        INF = 10**18
        while self.bfs(s, t):
            *self.it, = map(iter, self.G)
            f = INF
            while f:
                f = self.dfs(s, t, INF)
                flow += f
        return flow

・ポラード・ロー素因数分解
def gcd(a, b):
    while a:
        a, b = b%a, a
    return b

def is_prime(n):
    if n == 2:
        return 1
    if n == 1 or n%2 == 0:
        return 0

    m = n - 1
    lsb = m & -m
    s = lsb.bit_length()-1
    d = m // lsb

    test_numbers = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]

    for a in test_numbers:
        if a == n:
            continue
        x = pow(a,d,n)
        r = 0
        if x == 1:
            continue
        while x != m:
            x = pow(x,2,n)
            r += 1
            if x == 1 or r == s:
                return 0
    return 1

def find_prime_factor(n):
    if n%2 == 0:
        return 2

    m = int(n**0.125)+1

    for c in range(1,n):
        f = lambda a: (pow(a,2,n)+c)%n
        y = 0
        g = q = r = 1
        k = 0
        while g == 1:
            x = y
            while k < 3*r//4:
                y = f(y)
                k += 1
            while k < r and g == 1:
                ys = y
                for _ in range(min(m, r-k)):
                    y = f(y)
                    q = q*abs(x-y)%n
                g = gcd(q,n)
                k += m
            k = r
            r *= 2
        if g == n:
            g = 1
            y = ys
            while g == 1:
                y = f(y)
                g = gcd(abs(x-y),n)
        if g == n:
            continue
        if is_prime(g):
            return g
        elif is_prime(n//g):
            return n//g
        else:
            return find_prime_factor(g)

def factorize(n):
    res = []
    while not is_prime(n) and n > 1:  # nが合成数である間nの素因数の探索を繰り返す
        p = find_prime_factor(n)
        s = 0
        while n%p == 0:  # nが素因数pで割れる間割り続け、出力に追加
            n //= p
            s += 1
        res.append((p, s))
    if n > 1:  # n>1であればnは素数なので出力に追加
        res.append((n, 1))
    return res

def divisor(n):
    ans = [1]
    pf = factorize(n)
    for p, c in pf:
        L = len(ans)
        for i in range(L):
            v = 1
            for _ in range(c):
                v *= p
                ans.append(ans[i]*v)
    return sorted(ans)

・行列の積
def matrix(a, b):
    ans = [[0]*len(b[0]) for _ in range(len(a))]
    for i in range(len(a)):
        for j in range(len(b[0])):
            for k in range(len(b)):
                ans[i][j] += a[i][k]*b[k][j]%MOD
                ans[i][j] %= MOD
    return ans

・座標と行列から移動後の座標を求める
def place(a, b):
    X = sum(a[0][i]*b[i] for i in range(3))
    Y = sum(a[1][i]*b[i] for i in range(3))
    return X, Y

・変換行列
def OP(n, p):
    # 時計回りに90度回転
    if n == 1:
        A = [(0, 1, 0), (-1, 0, 0), (0, 0, 1)]
    # 反時計回りに90度回転
    elif n == 2:
        A = [(0, -1, 0), (1, 0, 0), (0, 0, 1)]
    # x軸pに対称な位置に移動
    elif n == 3:
        A = [(-1, 0, 2*p), (0, 1, 0), (0, 0, 1)]
    # y軸pに対称な位置に移動
    else:
        A = [(1, 0, 0), (0, -1, 2*p), (0, 0, 1)]
    return A

・WaveletMatrix
from itertools import accumulate
from typing import Optional

class BitVector:
    def __init__(self, B: list[int]):
        self.B = B
        self.acc = list(accumulate(B))

    def __len__(self) -> int:
        return len(self.B)

    def __getitem__(self, i: int) -> int:
        return self.B[i]

    def rank0(self, i: int) -> int:
        if i <= 0:
            return 0
        i = min(i, len(self))
        return i - self.rank1(i)

    def rank1(self, i: int) -> int:
        if i <= 0:
            return 0
        i = min(i, len(self))
        return self.acc[i - 1]

    def rank0_all(self) -> int:
        return self.rank0(len(self.B))

    def rank1_all(self) -> int:
        return self.rank1(len(self.B))

    def select0(self, k: int) -> Optional[int]:
        if (k <= 0) or (k > self.rank0_all()):
            return None

        left, right = 0, len(self)
        while (right - left) > 1:
            mid = (left + right) // 2
            if self.rank0(mid) < k:
                left = mid
            else:
                right = mid
        return left

    def select1(self, k: int) -> Optional[int]:
        if (k <= 0) or (k > self.rank1_all()):
            return None

        left, right = 0, len(self)
        while (right - left) > 1:
            mid = (left + right) // 2
            if self.rank1(mid) < k:
                left = mid
            else:
                right = mid
        return left

class WaveletMatrix:
    def __init__(self, T: list[int]):
        self.bit_size: int = max(T).bit_length() if T else 0
        self.wavelet_matrix: list[BitVector] = self._build(T)

    def _build(self, T: list[int]) -> list[BitVector]:
        wavelet_matrix: list[BitVector] = []
        for digit in range(self.bit_size)[::-1]:
            zeros = [t for t in T if not self._get_i_bit(t, digit + 1)]
            ones = [t for t in T if self._get_i_bit(t, digit + 1)]

            T = zeros + ones
            wavelet_matrix.append(BitVector([self._get_i_bit(t, digit) for t in T]))
        return wavelet_matrix

    def __len__(self) -> int:
        if len(self.wavelet_matrix) == 0:
            return 0
        return len(self.wavelet_matrix[0])

    def __getitem__(self, i: int) -> int:
        return self.access(i)

    def _get_i_bit(self, x: int, digit: int) -> int:
        return 1 & (x >> digit)

    def _next_range(self, B: BitVector, bit: int, left: int, right: int) -> tuple[int, int]:
        if bit == 0:
            left = B.rank0(left)
            right = B.rank0(right)
        else:
            left = B.rank0_all() + B.rank1(left)
            right = B.rank0_all() + B.rank1(right)
        return (left, right)

    def access(self, i: int) -> int:
        x = 0
        for digit, B in enumerate(self.wavelet_matrix):
            bit = B[i]
            x |= bit << (self.bit_size - digit - 1)

            if bit == 0:
                i = B.rank0(i + 1) - 1
            else:
                i = B.rank0_all() + B.rank1(i + 1) - 1
        return x

    # T[0..right)におけるxの出現回数
    def rank(self, x: int, right: int) -> int:
        return self.rank_range(x, 0, right)

    # T[left..right)におけるxの出現回数
    def rank_range(self, x: int, left: int, right: int) -> int:
        if (left >= right) or (x.bit_length() > self.bit_size) or (x < 0):
            return 0

        left = max(left, 0)
        right = min(right, len(self))
        for digit, B in enumerate(self.wavelet_matrix):
            x_bit = self._get_i_bit(x, self.bit_size - digit - 1)
            left, right = self._next_range(B, x_bit, left, right)
        return right - left

    # 元の配列Tのk個目のxの出現位置 (index)
    def select(self, x: int, k: int) -> Optional[int]:
        if not (0 <= x < 1 << self.bit_size):
            return None
        if k <= 0:
            return None

        # xが最終的な配列のどの範囲に入るか計算
        left, right = 0, len(self)
        for digit, B in enumerate(self.wavelet_matrix):
            x_bit = self._get_i_bit(x, self.bit_size - digit - 1)
            left, right = self._next_range(B, x_bit, left, right)

        if left >= right:
            return None

        # 上記範囲のk番目が, 元の配列で何番目か計算
        index = left + k - 1
        for digit, B in enumerate(self.wavelet_matrix[::-1]):
            if index is None:
                return None

            x_bit = self._get_i_bit(x, digit)
            if x_bit == 0:
                index = B.select0(index + 1)
            else:
                index = B.select1(index - (B.rank0_all() - 1))
        return index

    # 元の配列T[left..right)の中のk番目に小さい値
    def quantile(self, left: int, right: int, k: int) -> Optional[int]:
        if (left >= right) or (k <= 0) or (right - left < k):
            return None

        left = max(left, 0)
        right = min(right, len(self))

        x = 0
        for digit, B in enumerate(self.wavelet_matrix):
            num_zeros = B.rank0(right) - B.rank0(left)

            # 該当要素が0の中か or 1の中か
            bit = 0 if k <= num_zeros else 1
            left, right = self._next_range(B, bit, left, right)

            if bit == 1:
                k -= num_zeros
                x |= bit << (self.bit_size - digit - 1)
        return x

    # T[left..right)の0 <= x < upper となるxの個数
    def range_freq_to(self, left: int, right: int, upper: int) -> int:
        if (left >= right) or (upper <= 0):
            return 0

        # 全ての要素が < upper
        if upper.bit_length() > self.bit_size:
            return right - left

        cnt = 0
        left = max(left, 0)
        right = min(right, len(self))
        for digit, B in enumerate(self.wavelet_matrix):
            upper_bit = self._get_i_bit(upper, self.bit_size - digit - 1)
            if upper_bit == 1:
                cnt += B.rank0(right) - B.rank0(left)

            left, right = self._next_range(B, upper_bit, left, right)

        return cnt

    # T[left..right)のlower <= x となるxの個数
    def range_freq_from(self, left: int, right: int, lower: int) -> int:
        if (left >= right) or (lower > (1 << self.bit_size)):
            return 0

        left = max(left, 0)
        right = min(right, len(self))
        return (right - left) - self.range_freq_to(left, right, lower)

    # T[left..right)のlower <= x < upper となるxの個数
    def range_freq(self, left: int, right: int, lower: int, upper: int) -> int:
        if (left >= right) or (lower >= upper) or (lower > (1 << self.bit_size)):
            return 0

        return self.range_freq_to(left, right, upper) - self.range_freq_to(
            left, right, lower
        )

    # T[left..right)の中で0 <= x < upperを満たす最大のx
    def prev_value(self, left: int, right: int, upper: int) -> Optional[int]:
        cnt = self.range_freq_to(left, right, upper)
        if cnt == 0:
            return None
        return self.quantile(left, right, cnt)

    # T[left..right)の中で, lower <= x を満たす最小のx
    def next_value(self, left: int, right: int, lower: int) -> int:
        cnt = self.range_freq_from(left, right, lower)
        if cnt == 0:
            return None
        return self.quantile(left, right, right - left - cnt + 1)

・HopcroftKarp
import sys
sys.setrecursionlimit(10**6)

class HopcroftKarp:
    def __init__(self, N1, N2):
        self.N1 = N1
        self.N2 = N2
        self.G = [[] for _ in range(self.N1+1)]
        self.pair1 = [0]*(self.N1+1)
        self.pair2 = [0]*(self.N2+1)
        self.matching_size = -1
        
    def add_edge(self, fr, to):
        self.G[fr].append(to)
    
    def bfs(self):
        que = deque()
        for i in range(1, self.N1+1):
            if self.pair1[i] == 0:
                self.dist[i] = 0
                que.append(i)
            else:
                self.dist[i] = INF
        self.dist[0] = INF
        while que:
            n = que.popleft()
            if self.dist[n] < self.dist[0]:
                for v in self.G[n]:
                    if self.dist[self.pair2[v]] == INF:
                        self.dist[self.pair2[v]] = self.dist[n]+1
                        que.append(self.pair2[v])
        return self.dist[0] != INF

    def dfs(self, n):
        if n != 0:
            for v in self.G[n]:
                if self.dist[self.pair2[v]] == self.dist[n]+1:
                    if self.dfs(self.pair2[v]):
                        self.pair2[v] = n
                        self.pair1[n] = v
                        return True
            self.dist[n] = INF
            return False
        return True
    
    def flow(self):
        if self.matching_size != -1:
            return self.matching_size
        self.dist = [0]*(self.N1+1)
        ans = 0
        while self.bfs():
            for i in range(1, self.N1+1):
                if self.pair1[i] == 0 and self.dfs(i):
                    ans += 1
        self.matching_size = ans
        return ans
    
    def get_matching(self):
        if self.matching_size == -1:
            self.flow()
        ans = []
        for i in range(1, self.N1+1):
            if self.pair1[i] != 0:
                ans.append((i, self.pair1[i]))
        return ans
    
    def minimum_vertex_cover(self):
        if self.matching_size == -1:
            self.flow()
        return self.matching_size
    
    def maximum_independent_set(self):
        return self.N1+self.N2-self.minimum_vertex_cover()
    
    def minimum_edge_cover(self):
        F = [False]*(self.N1+self.N2+1)
        for n in range(1, self.N1+1):
            F[n] = True
            for v in self.G[n]:
                F[self.N1+v] = True
        if sum(F) < self.N1+self.N2:
            return -1
        if self.matching_size == -1:
            self.flow()
        return self.N1+self.N2-self.matching_size
    
    def preparation(self):
        if self.matching_size == -1:
            self.flow()
        L = self.N1+self.N2
        G = [[] for _ in range(L+1)]
        for n in range(1, self.N1+1):
            for v in self.G[n]:
                if self.pair1[n] == v:
                    G[self.N1+v].append(n)
                else:
                    G[n].append(self.N1+v)

        visited = [False]*(L+1)
        que = deque()
        for i in range(1, self.N1+1):
            if self.pair1[i] == 0:
                visited[i] = True
                que.append(i)
        while que:
            n = que.popleft()
            for v in G[n]:
                if not visited[v]:
                    visited[v] = True
                    que.append(v)
        return visited

    def get_minimum_vertex_cover(self):
        visited = self.preparation()
        ans1 = []
        ans2 = []
        for i in range(1, self.N1+self.N2+1):
            if i <= self.N1 and not visited[i]:
                ans1.append(i)
            elif self.N1+1 <= i and visited[i]:
                ans2.append(i-self.N1)
        return ans1, ans2
    
    def get_maximum_independent_set(self):
        visited = self.preparation()
        ans1 = []
        ans2 = []
        for i in range(1, self.N1+self.N2+1):
            if i <= self.N1 and visited[i]:
                ans1.append(i)
            elif self.N1+1 <= i and not visited[i]:
                ans2.append(i-self.N1)
        return ans1, ans2
    
    def get_minimum_edge_cover(self):
        cnt = self.minimum_edge_cover()
        if cnt == -1:
            return None
        ans = []
        pair = [-1]*(self.N1+self.N2+1)
        for n in range(1, self.N1+1):
            pair[n] = self.G[n][0]
            for v in self.G[n]:
                if pair[self.N1+v] == -1:
                    pair[self.N1+v] = n
        for i in range(1, self.N1+self.N2+1):
            if i <= self.N1 and self.pair1[i] != 0:
                ans.append((i, self.pair1[i]))
            elif i <= self.N1 and self.pair1[i] == 0:
                ans.append((i, pair[i]))
            elif self.N1+1 <= i and self.pair2[i-self.N1] == 0:
                ans.append((pair[i], i-self.N1))
        return ans

・Suffix Array(SA-IS)
from collections import Counter

# SA-IS (O(nlogn))
# s: 文字列
def sais(s):
    uniq = list(set(s))
    uniq.sort()
    return sais_rec(list(map({e: i+1 for i, e in enumerate(uniq)}.__getitem__, s)), len(uniq))
def sais_rec(lst, num):
    L = len(lst)
    if L < 2:
        return lst + [0]
    lst = lst + [0]
    L += 1
    res = [-1] * L
    t = [1] * L
    for i in range(L-2, -1, -1):
        t[i] = 1 if (lst[i] < lst[i+1] or (lst[i] == lst[i+1] and t[i+1])) else 0
    isLMS = [t[i-1] < t[i] for i in range(L)]
    LMS = [i for i in range(1, L) if t[i-1] < t[i]]
    LMSn = len(LMS)

    count = Counter(lst)
    tmp = 0
    cstart = [0]*(num+1)
    cend = [0]*(num+1)
    for key in range(num+1):
        cstart[key] = tmp
        cend[key] = tmp = tmp + count[key]

    cc_it = [iter(range(e-1, s-1, -1)) for s, e in zip(cstart, cend)]
    for e in reversed(LMS):
        res[next(cc_it[lst[e]])] = e

    cs_it = [iter(range(s, e)) for s, e in zip(cstart, cend)]
    ce_it = [iter(range(e-1, s-1, -1)) for s, e in zip(cstart, cend)]
    for e in res:
        if e > 0 and not t[e-1]:
            res[next(cs_it[lst[e-1]])] = e-1
    for e in reversed(res):
        if e > 0 and t[e-1]:
            res[next(ce_it[lst[e-1]])] = e-1

    name = 0; prev = -1
    pLMS = {}
    for e in res:
        if isLMS[e]:
            if prev == -1 or lst[e] != lst[prev]:
                name += 1; prev = e
            else:
                for i in range(1, L):
                    if lst[e+i] != lst[prev+i]:
                        name += 1; prev = e
                        break
                    if isLMS[e+i] or isLMS[prev+i]:
                        break
            pLMS[e] = name-1

    if name < LMSn:
        sublst = [pLMS[e] for e in LMS if e < L-1]
        ret = sais_rec(sublst, name-1)

        LMS = list(map(LMS.__getitem__, reversed(ret)))
    else:
        LMS = [e for e in reversed(res) if isLMS[e]]

    res = [-1] * L

    cc_it = [iter(range(e-1, s-1, -1)) for s, e in zip(cstart, cend)]
    for e in LMS:
        res[next(cc_it[lst[e]])] = e

    cs_it = [iter(range(s, e)) for s, e in zip(cstart, cend)]
    ce_it = [iter(range(e-1, s-1, -1)) for s, e in zip(cstart, cend)]

    for e in res:
        if e > 0 and not t[e-1]:
            res[next(cs_it[lst[e-1]])] = e-1
    for e in reversed(res):
        if e > 0 and t[e-1]:
            res[next(ce_it[lst[e-1]])] = e-1
    return res

# Longest Common Prefix
# (文字列s, 文字列長n, Suffix Array)を引数として与える
def LCP(s, n, sa):
    lcp = [-1]*(n+1)
    rank = [0]*(n+1)
    for i in range(n+1): rank[sa[i]] = i

    h = 0
    lcp[0] = 0
    for i in range(n):
        j = sa[rank[i] - 1]
        if h > 0: h -= 1
        while j+h < n and i+h < n and s[j+h]==s[i+h]:
            h += 1
        lcp[rank[i] - 1] = h
    return lcp

・最小費用流
# https://atcoder.jp/contests/practice2/submissions/33588016
from heapq import heappush, heappop

class MinCostFlow:
    """
    https://github.com/atcoder/ac-library/blob/master/atcoder/internal_csr.hpp
    https://github.com/atcoder/ac-library/blob/master/atcoder/mincostflow.hpp
    https://github.com/atcoder/ac-library/blob/master/document_en/mincostflow.md
    https://github.com/atcoder/ac-library/blob/master/document_ja/mincostflow.md
    """
    def __init__(self, n):
        self.n = n
        self._edges = []

    def add_edge(self, fr, to, cap, cost):
        assert 0 <= fr < self.n
        assert 0 <= to < self.n
        assert 0 <= cap
        assert 0 <= cost
        self._edges.append(self.edge(fr, to, cap, cost))
        return len(self._edges) - 1

    class edge:
        def __init__(self, fr, to, cap, cost):
            self.fr = fr
            self.to = to
            self.cap = cap
            self.flow = 0
            self.cost = cost

    def get_edge(self, i):
        assert 0 <= i < len(self._edges)
        return self._edges[i]

    def edges(self):
        return self._edges

    def flow(self, s, t, flow_limit=1<<60):
        return self.slope(s, t, flow_limit)[-1]

    def __csr(self, edges):
        # Compressed Sparse Row
        self.start = [0] * (self.n + 1)
        for fr, _ in edges:
            self.start[fr + 1] += 1
        for i in range(self.n):
            self.start[i + 1] += self.start[i]
        counter = self.start.copy()
        self.elist = [0] * len(edges)
        for fr, e in edges:
            self.elist[counter[fr]] = e
            counter[fr] += 1

    class _edge:
        def __init__(self, to, rev, cap, cost):
            self.to = to
            self.rev = rev
            self.cap = cap
            self.cost = cost

    def __g(self):
        degree = [0] * self.n
        redge_idx = [0] * self.m
        elist = [(0, None)] * (2 * self.m)
        now_elist = 0
        for i in range(self.m):
            e = self._edges[i]
            self.edge_idx[i] = degree[e.fr]
            degree[e.fr] += 1
            redge_idx[i] = degree[e.to]
            degree[e.to] += 1
            elist[now_elist] = (e.fr, self._edge(e.to, -1, e.cap - e.flow, e.cost))
            now_elist += 1
            elist[now_elist] = (e.to, self._edge(e.fr, -1, e.flow, -e.cost))
            now_elist += 1
        self.__csr(elist)
        for i in range(self.m):
            e = self._edges[i]
            self.edge_idx[i] += self.start[e.fr]
            redge_idx[i] += self.start[e.to]
            self.elist[self.edge_idx[i]].rev = redge_idx[i]
            self.elist[redge_idx[i]].rev = self.edge_idx[i]

    def slope(self, s, t, flow_limit=1<<60):
        assert 0 <= s < self.n
        assert 0 <= t < self.n
        assert s != t
        self.m = len(self._edges)
        self.edge_idx = [0] * self.m
        self.__g()
        result = self.__slope(s, t, flow_limit)
        for i in range(self.m):
            e = self.elist[self.edge_idx[i]]
            self._edges[i].flow = self._edges[i].cap - e.cap
        return result

    def __dual_ref(self, s, t):
        log = self.n.bit_length()
        mask = (1<<log) - 1
        dist = [1<<60] * self.n
        vis = [0] * self.n
        que_min = []
        que = []
        dist[s] = 0
        que_min.append(s)
        while que_min or que:
            if que_min:
                v = que_min.pop()
            else:
                v = heappop(que) & mask
            if vis[v]:
                continue
            vis[v] = 1
            if v == t:
                break
            # dist[v] = shortest(s, v) + dual[s] - dual[v]
            # dist[v] >= 0 (all reduced cost are positive)
            # dist[v] <= (n-1)C
            dual_v = self.dual[v]
            dist_v = dist[v]
            for i in range(self.start[v], self.start[v+1]):
                e = self.elist[i]
                if not e.cap:
                    continue
                # |-dual[e.to] + dual[v]| <= (n-1)C
                # cost <= C - -(n-1)C + 0 = nC
                cost = e.cost - self.dual[e.to] + dual_v
                if dist[e.to] - dist_v > cost:
                    dist_to = dist_v + cost
                    dist[e.to] = dist_to
                    self.prev_e[e.to] = e.rev
                    if dist_to == dist_v:
                        que_min.append(e.to)
                    else:
                        heappush(que, dist_to<<log | e.to)
        if not vis[t]:
            return False
        for v in range(self.n):
            if not vis[v]:
                continue
            # dual[v]
            # = dual[v] - dist[t] + dist[v]
            # = dual[v] - (shortest(s, t) + dual[s] - dual[t]) + (shortest(s, v) + dual[s] - dual[v])
            # = - shortest(s, t) + dual[t] + shortest(s, v)
            # = shortest(s, v) - shortest(s, t)
            # >= 0 - (n-1)C
            self.dual[v] -= dist[t] - dist[v]
        return True

    def __slope(self, s, t, flow_limit):
        # variants (C = maxcost):
        # -(n-1)C <= dual[s] <= dual[i] <= dual[t] = 0
        # reduced cost (= e.cost + dual[e.from] - dual[e.to]) >= 0 for all edge
        self.dual = [0] * self.n
        self.prev_e = [0] * self.n
        flow = 0
        cost = 0
        prev_cost_per_flow = -1
        result = [(0, 0)]
        while flow < flow_limit:
            if not self.__dual_ref(s, t):
                break
            c = flow_limit - flow
            v = t
            while v != s:
                c = min(c, self.elist[self.elist[self.prev_e[v]].rev].cap)
                v = self.elist[self.prev_e[v]].to
            v = t
            while v != s:
                e = self.elist[self.prev_e[v]]
                e.cap += c
                self.elist[e.rev].cap -= c
                v = self.elist[self.prev_e[v]].to
            d = -self.dual[s]
            flow += c
            cost += c * d
            if prev_cost_per_flow == d:
                result.pop()
            result.append((flow, cost))
            prev_cost_per_flow = d
        return result

・エラトステネスのふるいを用いた高速素因数分解と高速約数列挙
class Eratosthenes:
    def __init__(self, n):
        self.isPrime = [True]*(n+1)
        self.minfactor = [-1]*(n+1)
        self.isPrime[0], self.isPrime[1] = False, False
        self.minfactor[1] = 1
        for i in range(2, n+1):
            if self.isPrime[i]:
                self.minfactor[i] = i
                for j in range(i*i, n+1, i):
                    self.isPrime[j] = False
                    if self.minfactor[j] == -1:
                        self.minfactor[j] = i
    
    def factorize(self, n):
        factor = []
        while n > 1:
            p = self.minfactor[n]
            cnt = 0
            while self.minfactor[n] == p:
                n //= p
                cnt += 1
            factor.append((p, cnt))
        return factor
    
    def divisor(self, n):
        ans = [1]
        pf = self.factorize(n)
        for p, c in pf:
            L = len(ans)
            for i in range(L):
                v = 1
                for _ in range(c):
                    v *= p
                    ans.append(ans[i]*v)
        return ans

・高速ゼータ変換、高速メビウス変換
def Eratosthenes(n):
    isPrime = [True]*(n+1)
    isPrime[0], isPrime[1] = False, False
    for i in range(2, n+1):
        if isPrime[i]:
            for j in range(i*i, n+1, i):
                isPrime[j] = False
    return isPrime

def fast_zeta(F):
    isPrime = Eratosthenes(len(F))
    print(F)
    for i in range(2, len(F)):
        if isPrime[i]:
            for j in range((len(F)-1)//i, 0, -1):
                F[j] += F[j*i]
            print(F)

def fast_mobius(F):
    isPrime = Eratosthenes(len(F))
    for i in range(2, len(F)):
        if isPrime[i]:
            for j in range(1, (len(F)-1)//i+1):
                F[j] -= F[j*i]

・メビウス関数値の列挙
class Eratosthenes:
    def __init__(self, n):
        self.isPrime = [True]*(n+1)
        self.isPrime[0], self.isPrime[1] = False, False
        self.mobius = [1]*(n+1)
        for i in range(2, n+1):
            if self.isPrime[i]:
                self.mobius[i] = -1
                for j in range(i*2, n+1, i):
                    self.isPrime[j] = False
                    if j//i%i == 0:
                        self.mobius[j] = 0
                    else:
                        self.mobius[j] *= -1

・オイラーのφ関数
def Euler(n):
    div = divisor(n)
    ans = 0
    E = Eratosthenes(n)
    for d in div:
        ans += n//d*E.mobius[d]
    return ans

・座標圧縮
def compress(A):
    S = sorted(set(A))
    D = dict()
    for i in range(len(S)):
        D[S[i]] = i
    return D

・マージソートツリー(X以下や以上の個数)
class MergeSortTree:
    def __init__(self, init_val):
        n = len(init_val)
        self.n = n
        self.num = 1<<(n-1).bit_length()
        self.tree = [[] for _ in range(self.num*2)]
        for i in range(n):
            self.tree[self.num+i].append(init_val[i])
        for i in range(self.num-1, 0, -1):
            left, right = 2*i, 2*i+1
            idxL, idxR = 0, 0
            while idxL < len(self.tree[left]) or idxR < len(self.tree[right]):
                if idxL == len(self.tree[left]):
                    self.tree[i].append(self.tree[right][idxR])
                    idxR += 1
                elif idxR == len(self.tree[right]):
                    self.tree[i].append(self.tree[left][idxL])
                    idxL += 1
                else:
                    if self.tree[left][idxL] <= self.tree[right][idxR]:
                        self.tree[i].append(self.tree[left][idxL])
                        idxL += 1
                    else:
                        self.tree[i].append(self.tree[right][idxR])
                        idxR += 1
    
    # bisectのleftとrightを書き換えれば、Xより小さい数 or Xより大きい数 のクエリにも対応可能
    # sum(A[i] <= X for i in range(l, r))
    def query1(self, l, r, X):
        ans = 0
        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                ans += bisect_right(self.tree[l], X)
                l += 1
            if r & 1:
                ans += bisect_right(self.tree[r-1], X)
            l >>= 1
            r >>= 1
        return ans
    # sum(A[i] >= X for i in range(l, r))
    def query2(self, l, r, X):
        ans = 0
        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                ans += len(self.tree[l])-bisect_left(self.tree[l], X)
                l += 1
            if r & 1:
                ans += len(self.tree[r-1])-bisect_left(self.tree[r-1], X)
            l >>= 1
            r >>= 1
        return ans
    # sum(leftX <= A[i] <= rightX for i in range(l, r))
    def query3(self, l, r, leftX, rightX):
        ans = r-l
        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                ans -= bisect_left(self.tree[l], leftX)
                ans -= len(self.tree[l])-bisect_right(self.tree[l], rightX)
                l += 1
            if r & 1:
                ans -= bisect_left(self.tree[r-1], leftX)
                ans -= len(self.tree[r-1])-bisect_right(self.tree[r-1], rightX)
            l >>= 1
            r >>= 1
        return ans

・マージソートツリー(X以下や以上の個数、総和)
class MergeSortTree:
    def __init__(self, init_val):
        n = len(init_val)
        self.n = n
        self.num = 1<<(n-1).bit_length()
        self.tree = [[] for _ in range(self.num*2)]
        self.cum = [[0] for _ in range(self.num*2)]
        for i in range(n):
            self.tree[self.num+i].append(init_val[i])
        for i in range(self.num-1, 0, -1):
            left, right = 2*i, 2*i+1
            idxL, idxR = 0, 0
            while idxL < len(self.tree[left]) or idxR < len(self.tree[right]):
                if idxL == len(self.tree[left]):
                    self.tree[i].append(self.tree[right][idxR])
                    idxR += 1
                elif idxR == len(self.tree[right]):
                    self.tree[i].append(self.tree[left][idxL])
                    idxL += 1
                else:
                    if self.tree[left][idxL] <= self.tree[right][idxR]:
                        self.tree[i].append(self.tree[left][idxL])
                        idxL += 1
                    else:
                        self.tree[i].append(self.tree[right][idxR])
                        idxR += 1
        for i in range(1, self.num*2):
            for j in range(len(self.tree[i])):
                self.cum[i].append(self.cum[i][-1]+self.tree[i][j])
    
    # bisectのleftとrightを書き換えれば、Xより小さい数 or Xより大きい数 のクエリにも対応可能
    # sum(A[i] <= X for i in range(l, r))
    def query1(self, l, r, X):
        ans = 0
        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                ans += bisect_right(self.tree[l], X)
                l += 1
            if r & 1:
                ans += bisect_right(self.tree[r-1], X)
            l >>= 1
            r >>= 1
        return ans
    # sum(A[i] >= X for i in range(l, r))
    def query2(self, l, r, X):
        ans = 0
        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                ans += len(self.tree[l])-bisect_left(self.tree[l], X)
                l += 1
            if r & 1:
                ans += len(self.tree[r-1])-bisect_left(self.tree[r-1], X)
            l >>= 1
            r >>= 1
        return ans
    # sum(leftX <= A[i] <= rightX for i in range(l, r))
    def query3(self, l, r, leftX, rightX):
        ans = r-l
        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                ans -= bisect_left(self.tree[l], leftX)
                ans -= len(self.tree[l])-bisect_right(self.tree[l], rightX)
                l += 1
            if r & 1:
                ans -= bisect_left(self.tree[r-1], leftX)
                ans -= len(self.tree[r-1])-bisect_right(self.tree[r-1], rightX)
            l >>= 1
            r >>= 1
        return ans
    # sum(A[i] for i in range(l, r) if A[i] <= X)
    def query4(self, l, r, X):
        ans = 0
        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                b = bisect_right(self.tree[l], X)
                ans += self.cum[l][b]
                l += 1
            if r & 1:
                b = bisect_right(self.tree[r-1], X)
                ans += self.cum[r-1][b]
            l >>= 1
            r >>= 1
        return ans
    # sum(A[i] for i in range(l, r) if A[i] >= X)
    def query5(self, l, r, X):
        ans = 0
        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                b = bisect_left(self.tree[l], X)
                ans += self.cum[l][-1]-self.cum[l][b]
                l += 1
            if r & 1:
                b = bisect_left(self.tree[r-1], X)
                ans += self.cum[r-1][-1]-self.cum[r-1][b]
            l >>= 1
            r >>= 1
        return ans
    # sum(A[i] for i in range(l, r) if leftX <= A[i] <= rightX)
    def query6(self, l, r, leftX, rightX):
        ans = 0
        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                left = bisect_left(self.tree[l], leftX)
                right = bisect_right(self.tree[l], rightX)
                ans += self.cum[l][right]-self.cum[l][left]
                l += 1
            if r & 1:
                left = bisect_left(self.tree[r-1], leftX)
                right = bisect_right(self.tree[r-1], rightX)
                ans += self.cum[r-1][right]-self.cum[r-1][left]
            l >>= 1
            r >>= 1
        return ans

・行列の積
def matrix(a, b):
    ans = [[0]*len(b[0]) for _ in range(len(a))]
    for i in range(len(a)):
        for j in range(len(b[0])):
            ans[i][j] = sum(a[i][k]*b[k][j] for k in range(len(b)))
    return ans

・中国剰余定理
def CRT(B, M):
    r, m = 0, 1
    for i in range(len(B)):
        d, x, y = extended_euclid(m, M[i])
        if (B[i]-r)%d != 0:
            return 0, -1
        tmp = (B[i]-r)//d*x%(M[i]//d)
        r += m*tmp
        m *= M[i]//d
    return r, m

・BIT
class BIT:
    def __init__(self, A):
        self.size = len(A)
        self.bit = [0]*(len(A)+1)
        for i in range(len(A)):
            self.add(i, A[i])

    def sum(self, i):
        i += 1
        ans = 0
        while i > 0:
            ans += self.bit[i]
            i -= -i&i
        return ans
    
    def query(self, l, r):
        if l == 0:
            return self.sum(r-1)
        else:
            return self.sum(r-1)-self.sum(l-1)
    
    def add(self, i, x):
        i += 1
        while i <= self.size:
            self.bit[i] += x
            i += -i&i

・線分の交差判定
def judge(ax, ay, bx, by, cx, cy, dx, dy):
    s = (ax-bx)*(cy-ay)-(ay-by)*(cx-ax)
    t = (ax-bx)*(dy-ay)-(ay-by)*(dx-ax)
    if s*t > 0:
        return False
    s = (cx-dx)*(ay-cy)-(cy-dy)*(ax-cx)
    t = (cx-dx)*(by-cy)-(cy-dy)*(bx-cx)
    if s*t > 0:
        return False
    return True

・二次元累積和
class cum2:
    def __init__(self, A):
        self.cum = [[0]*(len(A[0])+1) for _ in range(len(A)+1)]
        for i in range(len(A)):
            for j in range(len(A[0])):
                self.cum[i+1][j+1] = A[i][j]
        for i in range(1, len(A)+1):
            for j in range(2, len(A[0])+1):
                self.cum[i][j] += self.cum[i][j-1]
        for i in range(2, len(A)+1):
            for j in range(1, len(A[0])+1):
                self.cum[i][j] += self.cum[i-1][j]
    def query(self, lh, rh, lw, rw):
        return self.cum[rh+1][rw+1]+self.cum[lh][lw]-self.cum[rh+1][lw]-self.cum[lh][rw+1]

・三次元累積和
class cum3:
    def __init__(self, A):
        self.cum = [[[0]*(len(A[0][0])+1) for _ in range(len(A[0])+1)] for _ in range(len(A)+1)]
        for i in range(len(A)):
            for j in range(len(A[0])):
                for k in range(len(A[0][0])):
                    self.cum[i+1][j+1][k+1] = A[i][j][k]
        for i in range(1, len(A)+1):
            for j in range(1, len(A[0])+1):
                for k in range(2, len(A[0][0])+1):
                    self.cum[i][j][k] += self.cum[i][j][k-1]
        for i in range(1, len(A)+1):
            for j in range(2, len(A[0])+1):
                for k in range(1, len(A[0][0])+1):
                    self.cum[i][j][k] += self.cum[i][j-1][k]
        for i in range(2, len(A)+1):
            for j in range(1, len(A[0])+1):
                for k in range(1, len(A[0][0])+1):
                    self.cum[i][j][k] += self.cum[i-1][j][k]
    def query(self, lh, rh, ld, rd, lw, rw):
        return (self.cum[rh+1][rd+1][rw+1]+self.cum[rh+1][ld][lw]-self.cum[rh+1][rd+1][lw]-self.cum[rh+1][ld][rw+1]
                -self.cum[lh][rd+1][rw+1]-self.cum[lh][ld][lw]+self.cum[lh][rd+1][lw]+self.cum[lh][ld][rw+1])

・LowLink
class LowLink:
    def __init__(self, N):
        self.N = N
        self.M = 0
        self.G = [[] for _ in range(N)]
    
    def add_edge(self, u, v):
        self.G[u].append((v, self.M))
        self.G[v].append((u, self.M))
        self.M += 1
    
    @bootstrap
    def dfs(self, n, parent):
        self.visited[n] = True
        self.ord[n], self.low[n] = self.cnt, self.cnt
        self.cnt += 1
        is_ap = False
        child = 0
        for v, idx in self.G[n]:
            if not self.visited[v]:
                child += 1
                yield self.dfs(v, idx)
                self.low[n] = min(self.low[n], self.low[v])
                if parent != -1 and self.ord[n] <= self.low[v]:
                    is_ap = True
                if self.ord[n] < self.low[v]:
                    self.bridge.append(idx)
            elif idx != parent:
                self.low[n] = min(self.low[n], self.ord[v])
        if parent == -1 and 2 <= child:
            is_ap = True
        if is_ap:
            self.articulation_points.append(n)
        yield

    def find(self):
        self.ord = [-1]*self.N
        self.low = [-1]*self.N
        self.visited = [False]*self.N
        self.cnt = 0
        self.articulation_points = []
        self.bridge = []
        for i in range(self.N):
            if not self.visited[i]:
                self.dfs(i, -1)
        return sorted(self.articulation_points), sorted(self.bridge)

・Trie木
class Trie:
    def __init__(self, N, type):
        self.tree = [[-1]*26 for _ in range(N+1)]
        self.arrive = [0]*(N+1)
        self.last = [0]*(N+1)
        self.nex = 1
        if type == 0:
            self.base = ord("a")
        else:
            self.base = ord("A")
    
    def insert(self, S):
        now = 0
        self.arrive[now] += 1
        for s in S:
            if self.tree[now][ord(s)-self.base] == -1:
                self.tree[now][ord(s)-self.base] = self.nex
                now = self.nex
                self.nex += 1
            else:
                now = self.tree[now][ord(s)-self.base]
            self.arrive[now] += 1
        self.last[now] += 1
    
    def search(self, S):
        now = 0
        for s in S:
            if self.tree[now][ord(s)-self.base] == -1:
                return 0
            now = self.tree[now][ord(s)-self.base]
        return self.last[now]
    
    def start_with(self, S):
        now = 0
        for s in S:
            if self.tree[now][ord(s)-self.base] == -1:
                return 0
            now = self.tree[now][ord(s)-self.base]
        return self.arrive[now]

    def count(self):
        return self.arrive[0]

・分割
# dp[i][j] jをi以下の数字で分割する個数
def division1(n):
    dp = [[0]*(n+1) for _ in range(n+1)]
    dp[0][0] = 1
    for i in range(1, n+1):
        for j in range(n+1):
            if j-i >= 0:
                dp[i][j] = (dp[i-1][j]+dp[i][j-i])%MOD
            else:
                dp[i][j] = dp[i-1][j]
    return dp
# dp[i][j] iを長さがjの数字に分割する個数
def division2(n):
    dp = [[0]*(n+1) for _ in range(n+1)]
    dp[0][0] = 1
    for i in range(1, n+1):
        for j in range(1, n+1):
            if i-j >= 0:
                dp[i][j] = (dp[i-1][j-1]+dp[i-j][j])%MOD
            else:
                dp[i][j] = dp[i-1][j-1]
    return dp
# dp[i][j] iを長さがj以下の数字に分割する個数
def division3(n):
    dp = [[0]*(n+1) for _ in range(n+1)]
    dp[0][0] = 1
    for i in range(1, n+1):
        for j in range(1, n+1):
            if i-j >= 0:
                dp[i][j] = (dp[i][j-1]+dp[i-j][j])%MOD
            else:
                dp[i][j] = dp[i][j-1]
    return dp

・SortedSet(tatyam)
# https://github.com/tatyam-prime/SortedSet/blob/main/SortedSet.py
import math
from bisect import bisect_left, bisect_right
from typing import Generic, Iterable, Iterator, List, Tuple, TypeVar, Optional
T = TypeVar('T')

class SortedSet(Generic[T]):
    BUCKET_RATIO = 16
    SPLIT_RATIO = 24
    
    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)
        n = len(a)
        if any(a[i] > a[i + 1] for i in range(n - 1)):
            a.sort()
        if any(a[i] >= a[i + 1] for i in range(n - 1)):
            a, b = [], a
            for x in b:
                if not a or a[-1] != x:
                    a.append(x)
        n = self.size = len(a)
        num_bucket = int(math.ceil(math.sqrt(n / self.BUCKET_RATIO)))
        self.a = [a[n * i // num_bucket : n * (i + 1) // num_bucket] for i in range(num_bucket)]

    def __iter__(self) -> Iterator[T]:
        for i in self.a:
            for j in i: yield j

    def __reversed__(self) -> Iterator[T]:
        for i in reversed(self.a):
            for j in reversed(i): yield j
    
    def __eq__(self, other) -> bool:
        return list(self) == list(other)
    
    def __len__(self) -> int:
        return self.size
    
    def __repr__(self) -> str:
        return "SortedSet" + str(self.a)
    
    def __str__(self) -> str:
        s = str(list(self))
        return "{" + s[1 : len(s) - 1] + "}"

    def _position(self, x: T) -> Tuple[List[T], int, int]:
        "return the bucket, index of the bucket and position in which x should be. self must not be empty."
        for i, a in enumerate(self.a):
            if x <= a[-1]: break
        return (a, i, bisect_left(a, x))

    def __contains__(self, x: T) -> bool:
        if self.size == 0: return False
        a, _, i = self._position(x)
        return i != len(a) and a[i] == x

    def add(self, x: T) -> bool:
        "Add an element and return True if added. / O(√N)"
        if self.size == 0:
            self.a = [[x]]
            self.size = 1
            return True
        a, b, i = self._position(x)
        if i != len(a) and a[i] == x: return False
        a.insert(i, x)
        self.size += 1
        if len(a) > len(self.a) * self.SPLIT_RATIO:
            mid = len(a) >> 1
            self.a[b:b+1] = [a[:mid], a[mid:]]
        return True
    
    def _pop(self, a: List[T], b: int, i: int) -> T:
        ans = a.pop(i)
        self.size -= 1
        if not a: del self.a[b]
        return ans

    def discard(self, x: T) -> bool:
        "Remove an element and return True if removed. / O(√N)"
        if self.size == 0: return False
        a, b, i = self._position(x)
        if i == len(a) or a[i] != x: return False
        self._pop(a, b, i)
        return True
    
    def 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, i: int) -> T:
        "Return the i-th element."
        if i < 0:
            for a in reversed(self.a):
                i += len(a)
                if i >= 0: return a[i]
        else:
            for a in self.a:
                if i < len(a): return a[i]
                i -= len(a)
        raise IndexError
    
    def pop(self, i: int = -1) -> T:
        "Pop and return the i-th element."
        if i < 0:
            for b, a in enumerate(reversed(self.a)):
                i += len(a)
                if i >= 0: return self._pop(a, ~b, i)
        else:
            for b, a in enumerate(self.a):
                if i < len(a): return self._pop(a, b, i)
                i -= len(a)
        raise IndexError
    
    def index(self, x: T) -> int:
        "Count the number of elements < x."
        ans = 0
        for a in self.a:
            if a[-1] >= x:
                return ans + bisect_left(a, x)
            ans += len(a)
        return ans

    def index_right(self, x: T) -> int:
        "Count the number of elements <= x."
        ans = 0
        for a in self.a:
            if a[-1] > x:
                return ans + bisect_right(a, x)
            ans += len(a)
        return ans

・SortedMultiSet(tatyam)
# https://github.com/tatyam-prime/SortedSet/blob/main/SortedMultiset.py
import math
from bisect import bisect_left, bisect_right
from typing import Generic, Iterable, Iterator, List, Tuple, TypeVar, Optional
T = TypeVar('T')

class SortedMultiset(Generic[T]):
    BUCKET_RATIO = 16
    SPLIT_RATIO = 24
    
    def __init__(self, a: Iterable[T] = []) -> None:
        "Make a new SortedMultiset from iterable. / O(N) if sorted / O(N log N)"
        a = list(a)
        n = self.size = len(a)
        if any(a[i] > a[i + 1] for i in range(n - 1)):
            a.sort()
        num_bucket = int(math.ceil(math.sqrt(n / self.BUCKET_RATIO)))
        self.a = [a[n * i // num_bucket : n * (i + 1) // num_bucket] for i in range(num_bucket)]

    def __iter__(self) -> Iterator[T]:
        for i in self.a:
            for j in i: yield j

    def __reversed__(self) -> Iterator[T]:
        for i in reversed(self.a):
            for j in reversed(i): yield j
    
    def __eq__(self, other) -> bool:
        return list(self) == list(other)
    
    def __len__(self) -> int:
        return self.size
    
    def __repr__(self) -> str:
        return "SortedMultiset" + str(self.a)
    
    def __str__(self) -> str:
        s = str(list(self))
        return "{" + s[1 : len(s) - 1] + "}"

    def _position(self, x: T) -> Tuple[List[T], int, int]:
        "return the bucket, index of the bucket and position in which x should be. self must not be empty."
        for i, a in enumerate(self.a):
            if x <= a[-1]: break
        return (a, i, bisect_left(a, x))

    def __contains__(self, x: T) -> bool:
        if self.size == 0: return False
        a, _, i = self._position(x)
        return i != len(a) and a[i] == x

    def 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 = 1
            return
        a, b, i = self._position(x)
        a.insert(i, x)
        self.size += 1
        if len(a) > len(self.a) * self.SPLIT_RATIO:
            mid = len(a) >> 1
            self.a[b:b+1] = [a[:mid], a[mid:]]
    
    def _pop(self, a: List[T], b: int, i: int) -> T:
        ans = a.pop(i)
        self.size -= 1
        if not a: del self.a[b]
        return ans

    def discard(self, x: T) -> bool:
        "Remove an element and return True if removed. / O(√N)"
        if self.size == 0: return False
        a, b, i = self._position(x)
        if i == len(a) or a[i] != x: return False
        self._pop(a, b, i)
        return True

    def 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, i: int) -> T:
        "Return the i-th element."
        if i < 0:
            for a in reversed(self.a):
                i += len(a)
                if i >= 0: return a[i]
        else:
            for a in self.a:
                if i < len(a): return a[i]
                i -= len(a)
        raise IndexError
    
    def pop(self, i: int = -1) -> T:
        "Pop and return the i-th element."
        if i < 0:
            for b, a in enumerate(reversed(self.a)):
                i += len(a)
                if i >= 0: return self._pop(a, ~b, i)
        else:
            for b, a in enumerate(self.a):
                if i < len(a): return self._pop(a, b, i)
                i -= len(a)
        raise IndexError

    def index(self, x: T) -> int:
        "Count the number of elements < x."
        ans = 0
        for a in self.a:
            if a[-1] >= x:
                return ans + bisect_left(a, x)
            ans += len(a)
        return ans

    def index_right(self, x: T) -> int:
        "Count the number of elements <= x."
        ans = 0
        for a in self.a:
            if a[-1] > x:
                return ans + bisect_right(a, x)
            ans += len(a)
        return ans

・区間更新 区間和取得
class Node:
    def __init__(self, value, size):
        self.value = value
        self.size = size

def op(left, right):
    return Node(left.value+right.value, left.size+right.size)

def mapping(top, bottom):
    if top != INF:
        return Node(top*bottom.size, bottom.size)
    else:
        return bottom

def composition(top, bottom):
    if top != INF:
        return top
    else:
        return bottom

e = Node(0, 0)
ID = INF

・木の重心
@bootstrap
def dfs(n, pre):
    cnt = 1
    MAX = -(10**18)
    for i, v in enumerate(G[n]):
        if v != pre:
            c = yield dfs(v, n)
            cnt += c
            if MAX < c:
                MAX = c
                maxidx[n] = i
    size[n] = cnt
    yield size[n]

size = [-1]*N
maxidx = [-1]*N
dfs(0, -1)

@bootstrap
def dfs2(n):
    if size[G[n][maxidx[n]]] > N//2:
        yield (yield dfs2(G[n][maxidx[n]]))
    yield n

center = dfs2(0)

・3点を結ぶ三角形の面積
def area(x1, y1, x2, y2, x3, y3):
    return abs((x1-x3)*(y2-y3)-(x2-x3)*(y1-y3))/2

・ChatGPT用
The following code is what I wrote to solve a problem in an AtCoder contest. When using generative AI to translate programming languages during an ongoing AtCoder contest, there are the following restrictions: "It is absolutely necessary to include the original code at the beginning of the submission as a comment or similar." "Only translations that do not alter the algorithm are permitted. In particular, any changes that would affect the time complexity are strictly prohibited." For any parts that cannot be directly translated, please mark them as "FAILED" and leave them unconverted. Following these strict AtCoder rules, please translate the following code from Python to C++.

・文字と数字の変換
def code(s):
    return ord(s)-ord("a")
def codeR(n):
    return chr(ord("a")+n)

・組み合わせの数(k == 2 or k == 3)
def nC2(n):
    return n*(n-1)//2
def nC3(n):
    return n*(n-1)*(n-2)//6

・無限等比級数の和
def infinite(a, r):
    # a = 初項 r = 公比
    return inverse(a, 1-r)

・UnionFind(値を保持)
class UnionFind:
    def __init__(self, n, A):
        self.n = n
        self.parent_size = [-1]*n
        self.A = A[:]
 
    def leader(self, a):
        if self.parent_size[a] < 0:
            return a
        self.parent_size[a] = self.leader(self.parent_size[a])
        return self.parent_size[a]
 
    def merge(self, a, b):
        x, y = self.leader(a), self.leader(b)
        if x == y:
            return 
        a = self.A[x]
        if abs(self.parent_size[x]) < abs(self.parent_size[y]):
            x, y = y, x
        self.parent_size[x] += self.parent_size[y]
        self.parent_size[y] = x
        self.A[x] = a
        return 
    
    def __getitem__(self, n):
        return self.A[self.leader(n)]
    
    def update(self, n, a):
        self.A[self.leader(n)] = a
 
    def same(self, a, b):
        return self.leader(a) == self.leader(b)
 
    def size(self, a):
        return abs(self.parent_size[self.leader(a)])
 
    def groups(self):
        result = [[] for _ in range(self.n)]
        for i in range(self.n):
            result[self.leader(i)].append(i)
        return [r for r in result if r != []]

・UnionFind(値を演算)
def op(x, y):
    return 
class UnionFind:
    def __init__(self, n, A, op):
        self.n = n
        self.parent_size = [-1]*n
        self.A = A[:]
        self.op = op
 
    def leader(self, a):
        if self.parent_size[a] < 0:
            return a
        self.parent_size[a] = self.leader(self.parent_size[a])
        return self.parent_size[a]
 
    def merge(self, a, b):
        x, y = self.leader(a), self.leader(b)
        if x == y:
            return 
        l, r = self.A[x], self.A[y]
        if abs(self.parent_size[x]) < abs(self.parent_size[y]):
            x, y = y, x
        self.parent_size[x] += self.parent_size[y]
        self.parent_size[y] = x
        self.A[x] = self.op(l, r)
        return 
    
    def __getitem__(self, n):
        return self.A[self.leader(n)]
    
    def update(self, n, a):
        self.A[self.leader(n)] = a
 
    def same(self, a, b):
        return self.leader(a) == self.leader(b)
 
    def size(self, a):
        return abs(self.parent_size[self.leader(a)])
 
    def groups(self):
        result = [[] for _ in range(self.n)]
        for i in range(self.n):
            result[self.leader(i)].append(i)
        return [r for r in result if r != []]

・ランレングス圧縮
def RLE(A):
    ans = []
    cnt = 0
    for i in range(len(A)):
        cnt += 1
        if i+1 == len(A) or A[i] != A[i+1]:
            ans.append((A[i], cnt))
            cnt = 0
    return ans

def RLER(A):
    ans = []
    for s, c in A:
        ans.append(s*c)
    return "".join(ans)

・Manacher
def Manacher(S):
    C = [""]
    for s in S:
        C.append(s)
        C.append("")
    R = [0]*len(C)
    i = 0
    j = 0
    while i < len(C):
        while 0 <= i-j and i+j < len(C) and C[i-j] == C[i+j]:
            j += 1
        R[i] = j
        k = 1
        while 0 <= i-k and k+R[i-k] < j:
            R[i+k] = R[i-k]
            k += 1
        i += k
        j -= k
    odd = []
    even = []
    for i in range(1, len(C)-1):
        if i%2 == 1:
            odd.append(R[i]//2)
        else:
            even.append(R[i]//2)
    return odd, even

・凸包
def cross3(a, b, c):
    return (b[0]-a[0])*(c[1]-a[1]) - (b[1]-a[1])*(c[0]-a[0])

def convex_hull(ps):
    ps.sort()
    qs = []
    L = len(ps)
    for p in ps:
        # 一直線上で高々2点にする場合は ">=" にする
        while len(qs) > 1 and cross3(qs[-1], qs[-2], p) > 0:
            qs.pop()
        qs.append(p)
    t = len(qs)
    for i in range(L-2, -1, -1):
        p = ps[i]
        while len(qs) > t and cross3(qs[-1], qs[-2], p) > 0:
            qs.pop()
        qs.append(p)
    return qs

A = []
IN = [-1]*N
OUT = [-1]*N
dfs(0, -1, 0)

・Auxiliary Tree
class AuxiliaryTree:
    def __init__(self, N, G):
        self.N = N
        self.G = G
        self.IN = [0]*N
        self.OUT = [0]*N
        self.depth = [0]*N
        self.E = []
        self.dfs(0, -1, 0)
        self.L = len(self.E)
        self.lg = [0]*(self.L+1)
        self.make_sparse_table()

    @bootstrap
    def dfs(self, n, p, d):
        self.depth[n] = d
        self.IN[n] = len(self.E)
        self.E.append(n)
        for v in self.G[n]:
            if v == p:
                continue
            yield self.dfs(v, n, d+1)
            self.E.append(n)
        self.OUT[n] = len(self.E)
        self.E.append(n)
        yield
    
    def make_sparse_table(self):
        for i in range(2, self.L+1):
            self.lg[i] = self.lg[i>>1]+1
        self.st = [[self.L]*(self.L-(1<<i)+1) for i in range(self.lg[self.L]+1)]
        self.st[0] = self.E[:]
        b = 1
        for i in range(self.lg[self.L]):
            for j in range(self.L-(b<<1)+1):
                self.st[i+1][j] = (self.st[i][j] if self.depth[self.st[i][j]] <= self.depth[self.st[i][j+b]] else self.st[i][j+b])
            b <<= 1
    
    def lca(self, u, v):
        x, y = self.IN[u], self.IN[v]
        l = self.lg[y-x+1]
        return self.st[l][x] if self.depth[self.st[l][x]] <= self.depth[self.st[l][y-(1<<l)+1]] else self.st[l][y-(1<<l)+1]
    
    def query(self, v):
        nG = defaultdict(list)
        V = v[:]
        V.sort(key=self.IN.__getitem__)
        K = len(V)
        stack = [V[0]]
        for i in range(K-1):
            w = self.lca(V[i], V[i+1])
            if w != V[i]:
                last = stack.pop()
                while stack and self.depth[w] < self.depth[stack[-1]]:
                    d = abs(self.depth[stack[-1]]-self.depth[last])
                    nG[stack[-1]].append((last, d))
                    nG[last].append((stack[-1], d))
                    last = stack.pop()
                if not stack or stack[-1] != w:
                    stack.append(w)
                    V.append(w)
                d = abs(self.depth[w]-self.depth[last])
                nG[w].append((last, d))
                nG[last].append((w, d))
            stack.append(V[i+1])
        for i in range(len(stack)-1):
            d = abs(self.depth[stack[i]]-self.depth[stack[i+1]])
            nG[stack[i]].append((stack[i+1], d))
            nG[stack[i+1]].append((stack[i], d))
        return nG, stack[0]

・木の直径と重心
visited = [-1]*N
visited[0] = 0
que = deque()
que.append(0)
while que:
    n = que.popleft()
    for v in G[n]:
        if visited[v] == -1:
            visited[v] = visited[n]+1
            que.append(v)
idx = visited.index(max(visited))
visited = [-1]*N
visited[idx] = 0
pre = [-1]*N
que = deque()
que.append(idx)
while que:
    n = que.popleft()
    for v in G[n]:
        if visited[v] == -1:
            visited[v] = visited[n]+1
            que.append(v)
            pre[v] = n
D = max(visited)
idx = visited.index(D)
while visited[idx] > (D+1)//2:
    idx = pre[idx]
center1 = idx
center2 = -1
if D%2 == 1:
    center2 = pre[idx]

・高速フーリエ変換
class FFT():
    def primitive_root_constexpr(self,m):
        if m==2:return 1
        if m==167772161:return 3
        if m==469762049:return 3
        if m==754974721:return 11
        if m==998244353:return 3
        divs=[0]*20
        divs[0]=2
        cnt=1
        x=(m-1)//2
        while(x%2==0):x//=2
        i=3
        while(i*i<=x):
            if (x%i==0):
                divs[cnt]=i
                cnt+=1
                while(x%i==0):
                    x//=i
            i+=2
        if x>1:
            divs[cnt]=x
            cnt+=1
        g=2
        while(1):
            ok=True
            for i in range(cnt):
                if pow(g,(m-1)//divs[i],m)==1:
                    ok=False
                    break
            if ok:
                return g
            g+=1
    def bsf(self,x):
        res=0
        while(x%2==0):
            res+=1
            x//=2
        return res
    rank2=0
    root=[]
    iroot=[]
    rate2=[]
    irate2=[]
    rate3=[]
    irate3=[]
    
    def __init__(self,MOD):
        self.mod=MOD
        self.g=self.primitive_root_constexpr(self.mod)
        self.rank2=self.bsf(self.mod-1)
        self.root=[0 for i in range(self.rank2+1)]
        self.iroot=[0 for i in range(self.rank2+1)]
        self.rate2=[0 for i in range(self.rank2)]
        self.irate2=[0 for i in range(self.rank2)]
        self.rate3=[0 for i in range(self.rank2-1)]
        self.irate3=[0 for i in range(self.rank2-1)]
        self.root[self.rank2]=pow(self.g,(self.mod-1)>>self.rank2,self.mod)
        self.iroot[self.rank2]=pow(self.root[self.rank2],self.mod-2,self.mod)
        for i in range(self.rank2-1,-1,-1):
            self.root[i]=(self.root[i+1]**2)%self.mod
            self.iroot[i]=(self.iroot[i+1]**2)%self.mod
        prod=1;iprod=1
        for i in range(self.rank2-1):
            self.rate2[i]=(self.root[i+2]*prod)%self.mod
            self.irate2[i]=(self.iroot[i+2]*iprod)%self.mod
            prod=(prod*self.iroot[i+2])%self.mod
            iprod=(iprod*self.root[i+2])%self.mod
        prod=1;iprod=1
        for i in range(self.rank2-2):
            self.rate3[i]=(self.root[i+3]*prod)%self.mod
            self.irate3[i]=(self.iroot[i+3]*iprod)%self.mod
            prod=(prod*self.iroot[i+3])%self.mod
            iprod=(iprod*self.root[i+3])%self.mod
    def butterfly(self,a):
        n=len(a)
        h=(n-1).bit_length()
        
        LEN=0
        while(LEN<h):
            if (h-LEN==1):
                p=1<<(h-LEN-1)
                rot=1
                for s in range(1<<LEN):
                    offset=s<<(h-LEN)
                    for i in range(p):
                        l=a[i+offset]
                        r=a[i+offset+p]*rot
                        a[i+offset]=(l+r)%self.mod
                        a[i+offset+p]=(l-r)%self.mod
                    rot*=self.rate2[(~s & -~s).bit_length()-1]
                    rot%=self.mod
                LEN+=1
            else:
                p=1<<(h-LEN-2)
                rot=1
                imag=self.root[2]
                for s in range(1<<LEN):
                    rot2=(rot*rot)%self.mod
                    rot3=(rot2*rot)%self.mod
                    offset=s<<(h-LEN)
                    for i in range(p):
                        a0=a[i+offset]
                        a1=a[i+offset+p]*rot
                        a2=a[i+offset+2*p]*rot2
                        a3=a[i+offset+3*p]*rot3
                        a1na3imag=(a1-a3)%self.mod*imag
                        a[i+offset]=(a0+a2+a1+a3)%self.mod
                        a[i+offset+p]=(a0+a2-a1-a3)%self.mod
                        a[i+offset+2*p]=(a0-a2+a1na3imag)%self.mod
                        a[i+offset+3*p]=(a0-a2-a1na3imag)%self.mod
                    rot*=self.rate3[(~s & -~s).bit_length()-1]
                    rot%=self.mod
                LEN+=2
                
    def butterfly_inv(self,a):
        n=len(a)
        h=(n-1).bit_length()
        LEN=h
        while(LEN):
            if (LEN==1):
                p=1<<(h-LEN)
                irot=1
                for s in range(1<<(LEN-1)):
                    offset=s<<(h-LEN+1)
                    for i in range(p):
                        l=a[i+offset]
                        r=a[i+offset+p]
                        a[i+offset]=(l+r)%self.mod
                        a[i+offset+p]=(l-r)*irot%self.mod
                    irot*=self.irate2[(~s & -~s).bit_length()-1]
                    irot%=self.mod
                LEN-=1
            else:
                p=1<<(h-LEN)
                irot=1
                iimag=self.iroot[2]
                for s in range(1<<(LEN-2)):
                    irot2=(irot*irot)%self.mod
                    irot3=(irot*irot2)%self.mod
                    offset=s<<(h-LEN+2)
                    for i in range(p):
                        a0=a[i+offset]
                        a1=a[i+offset+p]
                        a2=a[i+offset+2*p]
                        a3=a[i+offset+3*p]
                        a2na3iimag=(a2-a3)*iimag%self.mod
                        a[i+offset]=(a0+a1+a2+a3)%self.mod
                        a[i+offset+p]=(a0-a1+a2na3iimag)*irot%self.mod
                        a[i+offset+2*p]=(a0+a1-a2-a3)*irot2%self.mod
                        a[i+offset+3*p]=(a0-a1-a2na3iimag)*irot3%self.mod
                    irot*=self.irate3[(~s & -~s).bit_length()-1]
                    irot%=self.mod
                LEN-=2
    def convolution(self,a,b):
        n=len(a);m=len(b)
        if not(a) or not(b):
            return []
        if min(n,m)<=40:
            res=[0]*(n+m-1)
            for i in range(n):
                for j in range(m):
                    res[i+j]+=a[i]*b[j]
                    res[i+j]%=self.mod
            return res
        z=1<<((n+m-2).bit_length())
        a=a+[0]*(z-n)
        b=b+[0]*(z-m)
        self.butterfly(a)
        self.butterfly(b)
        c=[(a[i]*b[i])%self.mod for i in range(z)]
        self.butterfly_inv(c)
        iz=pow(z,self.mod-2,self.mod)
        for i in range(n+m-1):
            c[i]=(c[i]*iz)%self.mod
        return c[:n+m-1]

・分数
from math import gcd

class Fraction:
    def __init__(self, top, bottom):
        if bottom == 0:
            raise ZeroDivisionError
        GCD = gcd(top, bottom)
        if bottom < 0:
            top = -top
            bottom = -bottom
        self.top = top//GCD
        self.bottom = bottom//GCD

    def _to_fraction(self, x):
        return x if isinstance(x, Fraction) else Fraction(x, 1)

    def __eq__(self, other):
        other = self._to_fraction(other)
        return self.top == other.top and self.bottom == other.bottom
    
    def __ne__(self, other):
        other = self._to_fraction(other)
        return self.top != other.top or self.bottom != other.bottom
    
    def __lt__(self, other):
        other = self._to_fraction(other)
        return self.top*other.bottom < self.bottom*other.top
    
    def __le__(self, other):
        other = self._to_fraction(other)
        return self.top*other.bottom <= self.bottom*other.top
    
    def __gt__(self, other):
        other = self._to_fraction(other)
        return self.top*other.bottom > self.bottom*other.top
    
    def __ge__(self, other):
        other = self._to_fraction(other)
        return self.top*other.bottom >= self.bottom*other.top
        
    def __add__(self, other):
        other = self._to_fraction(other)
        GCD = gcd(self.bottom, other.bottom)
        bottom = self.bottom*other.bottom//GCD
        top1 = self.top*(bottom//self.bottom)
        top2 = other.top*(bottom//other.bottom)
        return Fraction(top1+top2, bottom)

    def __sub__(self, other):
        other = self._to_fraction(other)
        GCD = gcd(self.bottom, other.bottom)
        bottom = self.bottom*other.bottom//GCD
        top1 = self.top*(bottom//self.bottom)
        top2 = other.top*(bottom//other.bottom)
        return Fraction(top1-top2, bottom)

    def __mul__(self, other):
        other = self._to_fraction(other)
        return Fraction(self.top*other.top, self.bottom*other.bottom)
    
    def __truediv__(self, other):
        other = self._to_fraction(other)
        return Fraction(self.top*other.bottom, self.bottom*other.top)
    
    def __radd__(self, other):
        return self+other
    
    def __rsub__(self, other):
        return self._to_fraction(other)-self
    
    def __rmul__(self, other):
        return self*other
    
    def __rtruediv__(self, other):
        return self._to_fraction(other)/self
    
    def __int__(self):
        return self.top//self.bottom
    
    def __float__(self):
        return self.top/self.bottom
    
    def __str__(self):
        return f"{self.top}/{self.bottom}"
    
    def __hash__(self):
        return hash((self.top, self.bottom))
    
    def __bool__(self):
        return self.top != 0
    
    def __neg__(self):
        return Fraction(-self.top, self.bottom)
    
    def __abs__(self):
        return Fraction(abs(self.top), self.bottom)
    
    def get(self):
        return self.top, self.bottom

・ランダムチェッカー
from random import randrange

def solve1(N, L, R, A):
    # 自分のプログラム
    pass

def solve2(N, L, R, A):
    # 愚直のプログラム
    pass

while True:
    # 入力データをランダムで生成する
    
    # 違う出力をした場合に出力して終了する
    if solve1() != solve2():
        break

・floor_sum
def floor_sum(n, m, a, b):
    ans = 0
    while True:
        if a >= m or a < 0:
            ans += n * (n - 1) * (a // m) // 2
            a %= m
        if b >= m or b < 0:
            ans += n * (b // m)
            b %= m
        y_max = a * n + b
        if y_max < m: break
        n, b, m, a = y_max // m, y_max % m, a, m
    return ans

・ハッシュ(Hack対策)
from random import randrange

H = randrange(1, 1<<60)
def Hash(n):
    return n^H

・ChatGPT 翻訳依頼
今からCodeforcesの問題文を与えるため、日本語に翻訳してください。
翻訳以外の用途で生成AIを使用することは禁止されているため、問題の解法については出力しないようにしてください。

・Convex Hull Trick(O(N))
class Convex_Hull_Trick:
    def __init__(self):
        self.que = deque()

    def check(self, f1, f2, f3):
        return (f2[0] - f1[0]) * (f3[1] - f2[1]) >= (f2[1] - f1[1]) * (f3[0] - f2[0])
    
    def f(self, f1, x):
        return f1[0]*x + f1[1]
    
    # add f_i(x) = a*x + b
    # 降順
    def add_line(self, a, b):
        f1 = (a, b)
        while len(self.que) >= 2 and self.check(self.que[-2], self.que[-1], f1):
            self.que.pop()
        self.que.append(f1)

    # min f_i(x)
    # 昇順
    def query(self, x):
        while len(self.que) >= 2 and self.f(self.que[0], x) >= self.f(self.que[1], x):
            self.que.popleft()
        return self.f(self.que[0], x)

・セグメント木(区間演算、一点取得)
def op(x, y):
    return 
class SegTree:
    def __init__(self, init_val, op, ide_ele):
        n = len(init_val)
        self.n = n
        self.op = op
        self.ide_ele = ide_ele
        self.num = 1 << (n - 1).bit_length()
        self.tree = [ide_ele] * 2 * self.num
        for i in range(n):
            self.tree[self.num + i] = init_val[i]

    def update(self, l, r, x):
        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                self.tree[l] = self.op(x, self.tree[l])
                l += 1
            if r & 1:
                self.tree[r - 1] = self.op(x, self.tree[r - 1])
            l >>= 1
            r >>= 1

    def query(self, k):
        ans = self.ide_ele
        k += self.num
        ans = self.op(ans, self.tree[k])
        while k > 1:
            ans = self.op(ans, self.tree[k>>1])
            k >>= 1
        return ans

・セグメント木(区間更新、一点取得)
class SegTree:
    def __init__(self, init_val):
        n = len(init_val)
        self.n = n
        self.num = 1 << (n - 1).bit_length()
        self.tree = [-1] * 2 * self.num
        self.rank = [-1] * 2 * self.num
        self.cnt = 0
        for i in range(n):
            self.tree[self.num + i] = init_val[i]
            self.rank[self.num + i] = self.cnt
        self.cnt += 1

    def update(self, l, r, x):
        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                self.tree[l] = x
                self.rank[l] = self.cnt
                l += 1
            if r & 1:
                self.tree[r - 1] = x
                self.rank[r - 1] = self.cnt
            l >>= 1
            r >>= 1
        self.cnt += 1

    def query(self, k):
        k += self.num
        ans = self.tree[k]
        MAX = self.rank[k]
        while k > 1:
            if MAX < self.rank[k>>1]:
                ans = self.tree[k>>1]
                MAX = self.rank[k>>1]
            k >>= 1
        return ans

・区間XOR
def XORSUM(n):
    if n%4 == 0:
        return n
    elif n%4 == 1:
        return 1
    elif n%4 == 2:
        return n+1
    else:
        return 0

def rangeXOR(l, r):
    return XORSUM(r)^XORSUM(l-1)

・BucketList(tatyam)
# https://github.com/tatyam-prime/SortedSet/blob/main/BucketList.py
import math
from typing import Generic, Iterable, Iterator, TypeVar
T = TypeVar('T')

class BucketList(Generic[T]):
    BUCKET_RATIO = 16
    SPLIT_RATIO = 24
    
    def __init__(self, a: Iterable[T] = []) -> None:
        a = list(a)
        n = self.size = len(a)
        num_bucket = int(math.ceil(math.sqrt(n / self.BUCKET_RATIO)))
        self.a = [a[n * i // num_bucket : n * (i + 1) // num_bucket] for i in range(num_bucket)]

    def __iter__(self) -> Iterator[T]:
        for i in self.a:
            for j in i: yield j

    def __reversed__(self) -> Iterator[T]:
        for i in reversed(self.a):
            for j in reversed(i): yield j
    
    def __eq__(self, other) -> bool:
        if len(self) != len(other): return False
        for x, y in zip(self, other):
            if x != y: return False
        return True
    
    def __len__(self) -> int:
        return self.size
    
    def __repr__(self) -> str:
        return "BucketList" + str(self.a)
    
    def __str__(self) -> str:
        return str(list(self))

    def __contains__(self, x: T) -> bool:
        "Return True if x is in the bucket list. / O(N)"
        for y in self:
            if x == y: return True
        return False
    
    def _insert(self, a: list[T], b: int, i: int, x: T) -> None:
        a.insert(i, x)
        self.size += 1
        if len(a) > len(self.a) * self.SPLIT_RATIO:
            mid = len(a) >> 1
            self.a[b:b+1] = [a[:mid], a[mid:]]

    def insert(self, i: int, x: T) -> None:
        "Insert x at the i-th position. / O(√N)"
        if self.size == 0:
            if i != 0 and i != -1: raise IndexError
            self.a = [[x]]
            self.size = 1
            return
        if i < 0:
            for b, a in enumerate(reversed(self.a)):
                i += len(a)
                if i >= 0: return self._insert(a, len(self.a) + ~b, i, x)
        else:
            for b, a in enumerate(self.a):
                if i <= len(a): return self._insert(a, b, i, x)
                i -= len(a)
        raise IndexError

    def append(self, x: T) -> None:
        "Append x to the end of the list. / amortized O(1)"
        if self.size == 0:
            self.a = [[x]]
            self.size = 1
            return
        a = self.a[-1]
        return self._insert(a, len(self.a) - 1, len(a), x)
    
    def extend(self, a: Iterable[T]) -> None:
        for x in a: self.append(x)
    
    def __getitem__(self, i: int) -> T:
        if i < 0:
            for a in reversed(self.a):
                i += len(a)
                if i >= 0: return a[i]
        else:
            for a in self.a:
                if i < len(a): return a[i]
                i -= len(a)
        raise IndexError
    
    def _pop(self, a: list[T], b: int, i: int) -> T:
        ans = a.pop(i)
        self.size -= 1
        if not a: del self.a[b]
        return ans
    
    def pop(self, i: int = -1) -> T:
        "Remove and return the i-th element. / O(√N) / O(-i) if i < 0"
        if i < 0:
            for b, a in enumerate(reversed(self.a)):
                i += len(a)
                if i >= 0: return self._pop(a, ~b, i)
        else:
            for b, a in enumerate(self.a):
                if i < len(a): return self._pop(a, b, i)
                i -= len(a)
        raise IndexError

    def count(self, x: T) -> int:
        "Return the number of occurrences of x. / O(N)"
        return sum(1 for y in self if x == y)

    def index(self, x: T) -> int:
        "Return the index of the first occurrence of x, raise ValueError if not found. / O(N)"
        for i, y in enumerate(self):
            if x == y: return i
        raise ValueError
    
    def remove(self, x: T) -> None:
        "Remove the first occurrence of x, raise ValueError if not found. / O(N)"
        self.pop(self.index(x))

    def clear(self) -> None:
        self.a = []
        self.size = 0

    def reverse(self) -> None:
        self.a.reverse()
        for a in self.a: a.reverse()

    def copy(self) -> 'BucketList[T]':
        return BucketList(self)

・Lucasの定理
class Lucas:
    def __init__(self, MOD):
        self.MOD = MOD
        self.comb = [[0]*self.MOD for _ in range(self.MOD)]
        self.comb[0][0] = 1
        for i in range(1, self.MOD):
            self.comb[i][0] = 1
            for j in range(1, i+1):
                self.comb[i][j] = (self.comb[i-1][j-1]+self.comb[i-1][j])%self.MOD
    
    def C(self, N, K):
        ans = 1
        while N:
            ans *= self.comb[N%self.MOD][K%self.MOD]
            ans %= self.MOD
            N //= self.MOD
            K //= self.MOD
        return ans

・ラベル
class Label:
    def __init__(self, N, A=[]):
        self.N = N
        if A:
            self.label = A[:]
        else:
            self.label = list(range(N))
        self.labelR = [-1]*self.N
        for i in range(self.N):
            self.labelR[self.label[i]] = i
    
    # ラベルがどの箱に貼られているか
    def __getitem__(self, n):
        return self.labelR[n]
    
    # 箱に貼られているラベルは何か
    def getLabel(self, n):
        return self.label[n]
    
    # ラベルの情報を元にスワップ
    def swap(self, l, r):
        self.label[self.labelR[l]], self.label[self.labelR[r]] = self.label[self.labelR[r]], self.label[self.labelR[l]]
        self.labelR[l], self.labelR[r] = self.labelR[r], self.labelR[l]

・動的セグメントツリー
class Node:
    def __init__(self, init_val):
        self.left = None
        self.right = None
        self.value = init_val
def op(x, y):
    if x[0]%2 == 0:
        return (x[0]+y[0], x[1]+y[1], x[2]+y[2])
    else:
        return (x[0]+y[0], x[1]+y[2], x[2]+y[1])
class DynamicSegmentTree:
    def __init__(self, L, R, op, init_val):
        self.root = Node(init_val)
        self.L = L
        self.R = R
        self.op = op
        self.init_val = init_val
    
    def update(self, idx, value):
        stack = [(self.root, self.L, self.R)]
        path = []
        while stack:
            node, s, e = stack.pop()
            path.append((node, s, e))
            if s == e:
                node.value = value
                break
            mid = (s+e)//2
            if idx <= mid:
                if not node.left:
                    node.left = Node(self.init_val)
                stack.append((node.left, s, mid))
            else:
                if not node.right:
                    node.right = Node(self.init_val)
                stack.append((node.right, mid+1, e))
        path.pop()
        while path:
            node, s, e = path.pop()
            node.value = self.op(node.left.value if node.left else self.init_val, node.right.value if node.right else self.init_val)
    
    def query(self, l, r):
        stack = [(self.root, self.L, self.R)]
        ans = self.init_val
        while stack:
            node, s, e = stack.pop()
            if not node or e < l or r < s:
                continue
            if l <= s and e <= r:
                ans = self.op(ans, node.value)
                continue
            mid = (s+e)//2
            stack.append((node.left, s, mid))
            stack.append((node.right, mid+1, e))
        return ans

・最大流
# https://github.com/not522/ac-library-python/blob/master/atcoder/maxflow.py
from typing import NamedTuple, Optional, List, cast

class MFGraph:
    class Edge(NamedTuple):
        src: int
        dst: int
        cap: int
        flow: int

    class _Edge:
        def __init__(self, dst: int, cap: int) -> None:
            self.dst = dst
            self.cap = cap
            self.rev: Optional[MFGraph._Edge] = None

    def __init__(self, n: int) -> None:
        self._n = n
        self._g: List[List[MFGraph._Edge]] = [[] for _ in range(n)]
        self._edges: List[MFGraph._Edge] = []

    def add_edge(self, src: int, dst: int, cap: int) -> int:
        assert 0 <= src < self._n
        assert 0 <= dst < self._n
        assert 0 <= cap
        m = len(self._edges)
        e = MFGraph._Edge(dst, cap)
        re = MFGraph._Edge(src, 0)
        e.rev = re
        re.rev = e
        self._g[src].append(e)
        self._g[dst].append(re)
        self._edges.append(e)
        return m

    def get_edge(self, i: int) -> Edge:
        assert 0 <= i < len(self._edges)
        e = self._edges[i]
        re = cast(MFGraph._Edge, e.rev)
        return MFGraph.Edge(
            re.dst,
            e.dst,
            e.cap + re.cap,
            re.cap
        )

    def edges(self) -> List[Edge]:
        return [self.get_edge(i) for i in range(len(self._edges))]

    def change_edge(self, i: int, new_cap: int, new_flow: int) -> None:
        assert 0 <= i < len(self._edges)
        assert 0 <= new_flow <= new_cap
        e = self._edges[i]
        e.cap = new_cap - new_flow
        assert e.rev is not None
        e.rev.cap = new_flow

    def flow(self, s: int, t: int, flow_limit: Optional[int] = None) -> int:
        assert 0 <= s < self._n
        assert 0 <= t < self._n
        assert s != t
        if flow_limit is None:
            flow_limit = cast(int, sum(e.cap for e in self._g[s]))

        current_edge = [0] * self._n
        level = [0] * self._n

        def fill(arr: List[int], value: int) -> None:
            for i in range(len(arr)):
                arr[i] = value

        def bfs() -> bool:
            fill(level, self._n)
            queue = []
            q_front = 0
            queue.append(s)
            level[s] = 0
            while q_front < len(queue):
                v = queue[q_front]
                q_front += 1
                next_level = level[v] + 1
                for e in self._g[v]:
                    if e.cap == 0 or level[e.dst] <= next_level:
                        continue
                    level[e.dst] = next_level
                    if e.dst == t:
                        return True
                    queue.append(e.dst)
            return False

        def dfs(lim: int) -> int:
            stack = []
            edge_stack: List[MFGraph._Edge] = []
            stack.append(t)
            while stack:
                v = stack[-1]
                if v == s:
                    flow = min(lim, min(e.cap for e in edge_stack))
                    for e in edge_stack:
                        e.cap -= flow
                        assert e.rev is not None
                        e.rev.cap += flow
                    return flow
                next_level = level[v] - 1
                while current_edge[v] < len(self._g[v]):
                    e = self._g[v][current_edge[v]]
                    re = cast(MFGraph._Edge, e.rev)
                    if level[e.dst] != next_level or re.cap == 0:
                        current_edge[v] += 1
                        continue
                    stack.append(e.dst)
                    edge_stack.append(re)
                    break
                else:
                    stack.pop()
                    if edge_stack:
                        edge_stack.pop()
                    level[v] = self._n
            return 0

        flow = 0
        while flow < flow_limit:
            if not bfs():
                break
            fill(current_edge, 0)
            while flow < flow_limit:
                f = dfs(flow_limit - flow)
                flow += f
                if f == 0:
                    break
        return flow

    def min_cut(self, s: int) -> List[bool]:
        visited = [False] * self._n
        stack = [s]
        visited[s] = True
        while stack:
            v = stack.pop()
            for e in self._g[v]:
                if e.cap > 0 and not visited[e.dst]:
                    visited[e.dst] = True
                    stack.append(e.dst)
        return visited

・Gauss-Jordanの掃き出し法(MOD)
def GaussJordan_MOD(A, is_extended):
    H, W = len(A), len(A[0])

    for i in range(H):
        for j in range(W):
            A[i][j] %= MOD

    rank = 0
    for j in range(W-is_extended):
        for i in range(rank, H):
            if A[i][j] != 0:
                pivot = i
                break
        else:
            continue
        A[pivot], A[rank] = A[rank], A[pivot]
        inv = pow(A[rank][j], -1, MOD)
        for i in range(W):
            A[rank][i] *= inv
            A[rank][i] %= MOD
        for i in range(H):
            if i == rank or A[i][j] == 0:
                continue
            mul = A[i][j]
            for k in range(W):
                A[i][k] -= A[rank][k]*mul%MOD
                A[i][k] %= MOD
        rank += 1

    return rank

・連立方程式(GaussJordan)
def linear_equation(A, B):
    H, W = len(A), len(A[0])
    for i in range(H):
        A[i].append(B[i])

    rank = GaussJordan_MOD(A, True)
    for i in range(rank, H):
        if A[i][W]:
            return None, None
    
    ans = [A[i][W] for i in range(rank)]
    C = A[:rank]
    for i in range(rank):
        C[i].pop()
    return C, ans

・二項係数(Nが大きいとき用)
def C(N, K):
    if N < K:
        return 0
    if N < K*2:
        K = N-K
    top = 1
    for i in range(N, N-K, -1):
        top *= i
        top %= MOD
    bottom = 1
    for i in range(1, K+1):
        bottom *= i
        bottom %= MOD
    return inverse(top, bottom)

・BinaryTrie
class BinaryTrie:
    def __init__(self, length):
        self.tree = [[-1]*2]
        self.arrive = [0]
        self.last = [0]
        self.nex = 1
        self.length = length
        self.all_xor = 0
    
    def BIT(self, bit, n):
        return bit>>n & 1
    
    def operate_xor(self, n):
        self.all_xor ^= n
    
    def count(self):
        return self.arrive[0]

    def find(self, n):
        now = 0
        for i in reversed(range(self.length)):
            nex = self.BIT(n, i)^self.BIT(self.all_xor, i)
            if self.tree[now][nex] != -1 and 1 <= self.arrive[self.tree[now][nex]]:
                now = self.tree[now][self.BIT(n, i)^self.BIT(self.all_xor, i)]
            else:
                return False
        return True
    
    def insert(self, n):
        now = 0
        self.arrive[now] += 1
        for i in reversed(range(self.length)):
            if self.tree[now][self.BIT(n, i)^self.BIT(self.all_xor, i)] == -1:
                self.tree[now][self.BIT(n, i)^self.BIT(self.all_xor, i)] = self.nex
                self.tree.append([-1]*2)
                self.arrive.append(0)
                self.last.append(0)
                now = self.nex
                self.nex += 1
            else:
                now = self.tree[now][self.BIT(n, i)^self.BIT(self.all_xor, i)]
            self.arrive[now] += 1
        self.last[now] += 1

    def delete(self, n):
        # 存在していることが前提
        now = 0
        self.arrive[now] -= 1
        for i in reversed(range(self.length)):
            now = self.tree[now][self.BIT(n, i)^self.BIT(self.all_xor, i)]
            self.arrive[now] -= 1
        self.last[now] -= 1
    
    def min_element(self, n=0):
        if self.count() == 0:
            return -1
        ans = 0
        now = 0
        for i in reversed(range(self.length)):
            bit = self.BIT(n, i)^self.BIT(self.all_xor, i)
            nex = self.tree[now][bit]
            if nex != -1 and 1 <= self.arrive[nex]:
                now = nex
                if bit:
                    ans |= 1<<i
            else:
                now = self.tree[now][bit^1]
                if not bit:
                    ans |= 1<<i
        return ans^self.all_xor
    
    def max_element(self, n=0):
        if self.count() == 0:
            return -1
        ans = 0
        now = 0
        for i in reversed(range(self.length)):
            bit = self.BIT(n, i)^self.BIT(self.all_xor, i)^1
            nex = self.tree[now][bit]
            if nex != -1 and 1 <= self.arrive[nex]:
                now = nex
                if bit:
                    ans |= 1<<i
            else:
                now = self.tree[now][bit^1]
                if not bit:
                    ans |= 1<<i
        return ans^self.all_xor
    
    def kth_smallest(self, k, n=0):
        k += 1
        if self.count() < k:
            return -1
        ans = 0
        now = 0
        for i in reversed(range(self.length)):
            bit = self.BIT(n, i)^self.BIT(self.all_xor, i)
            nex = self.tree[now][bit]
            if nex != -1 and k <= self.arrive[nex]:
                now = nex
                if bit:
                    ans |= 1<<i
            else:
                now = self.tree[now][bit^1]
                k -= self.arrive[nex] if nex != -1 else 0
                if not bit:
                    ans |= 1<<i
        return ans^self.all_xor
    
    def kth_largest(self, k, n=0):
        k += 1
        if self.count() < k:
            return -1
        ans = 0
        now = 0
        for i in reversed(range(self.length)):
            bit = self.BIT(n, i)^self.BIT(self.all_xor, i)^1
            nex = self.tree[now][bit]
            if nex != -1 and k <= self.arrive[nex]:
                now = nex
                if bit:
                    ans |= 1<<i
            else:
                now = self.tree[now][bit^1]
                k -= self.arrive[nex] if nex != -1 else 0
                if not bit:
                    ans |= 1<<i
        return ans^self.all_xor
    
    def freq(self, n):
        now = 0
        for i in reversed(range(self.length)):
            bit = self.BIT(n, i)^self.BIT(self.all_xor, i)
            if self.tree[now][bit] == -1:
                return 0
            now = self.tree[now][bit]
        return self.last[now]

・直線の方程式
def line_equation(x1, y1, x2, y2):
    a = y2-y1
    b = x1-x2
    c = x2*y1-x1*y2
    return a, b, c

・IntervalSet
class IntervalSet:
    def __init__(self):
        self.interval = SortedMultiset()
    
    def add(self, l, r):
        idx = self.interval.index((l, -1))
        cnt = r-l+1
        if 1 <= idx and l <= self.interval[idx-1][1]+1:
            l2, r2 = self.interval.pop(idx-1)
            cnt -= min(r2, r)-l+1
            idx -= 1
            l = l2
            r = max(r2, r)
        while idx < len(self.interval) and self.interval[idx][0] <= r+1:
            l2, r2 = self.interval.pop(idx)
            cnt -= min(r2, r)-l2+1
            r = max(r, r2)
        self.interval.add((l, r))
        return cnt

    def remove(self, l, r):
        idx = self.interval.index((l, -1))
        cnt = 0
        if 1 <= idx and l <= self.interval[idx-1][1]:
            l2, r2 = self.interval.pop(idx-1)
            cnt += min(r, r2)-l+1
            self.interval.add((l2, l-1))
            if r < r2:
                self.interval.add((r+1, r2))
        while idx < len(self.interval) and self.interval[idx][0] <= r:
            l2, r2 = self.interval.pop(idx)
            cnt += min(r2, r)-l2+1
            if r < r2:
                self.interval.add((r+1, r2))
        return cnt
    
    def add2(self, l, r):
        ans = []
        idx = self.interval.index((l, -1))
        pl = l
        if 1 <= idx and l <= self.interval[idx-1][1]+1:
            l2, r2 = self.interval.pop(idx-1)
            idx -= 1
            l = l2
            r = max(r2, r)
            pl = r2+1
        while idx < len(self.interval) and self.interval[idx][0] <= r+1:
            l2, r2 = self.interval.pop(idx)
            if pl < l2:
                ans.append((pl, l2-1))
            pl = r2+1
            r = max(r, r2)
        self.interval.add((l, r))
        if pl <= r:
            ans.append((pl, r))
        return ans

    def remove2(self, l, r):
        ans = []
        idx = self.interval.index((l, -1))
        if 1 <= idx and l <= self.interval[idx-1][1]:
            l2, r2 = self.interval.pop(idx-1)
            self.interval.add((l2, l-1))
            ans.append((l, min(r2, r)))
            if r < r2:
                self.interval.add((r+1, r2))
        while idx < len(self.interval) and self.interval[idx][0] <= r:
            l2, r2 = self.interval.pop(idx)
            ans.append((l2, min(r2, r)))
            if r < r2:
                self.interval.add((r+1, r2))
        return ans
    
    def find(self, x):
        idx = self.interval.index((x+1, -1))
        if idx == 0:
            return (-1, -1)
        l, r = self.interval[idx-1]
        if x <= r:
            return (l, r)
        else:
            return (-1, -1)

・Mo's algorithm
class Mo:
    def __init__(self, N, add_L, add_R, remove_L, remove_R, route=None):
        self.N = N
        self.add_L = add_L
        self.add_R = add_R
        self.remove_L = remove_L
        self.remove_R = remove_R
        self.route = route if route is not None else int(self.N**0.5)+1
    
    def solve(self, query):
        Q = len(query)
        bucket = [[] for _ in range(self.N//self.route+1)]
        for i, (l, r) in enumerate(query):
            l, r = l-1, r-1
            bucket[l//self.route].append((i, l, r))
        
        ans = [-1]*Q
        now = 0
        left = 0
        right = -1
        for idx, q in enumerate(bucket):
            for i, l, r in sorted(q, key=lambda x:x[2], reverse=idx%2):
                while l < left:
                    left -= 1
                    now = self.add_L(now, left)
                while right < r:
                    right += 1
                    now = self.add_R(now, right)
                while left < l:
                    now = self.remove_L(now, left)
                    left += 1
                while r < right:
                    now = self.remove_R(now, right)
                    right -= 1
                ans[i] = now
        return ans

・Baby-step Giant-step
def BSGS(A, G, P):
    route = isqrt(P)+1
    D = dict()
    SUM = 1
    for i in range(route):
        if SUM not in D:
            D[SUM] = i
        SUM *= A
        SUM %= P
    C = pow(A, -route, P)
    for i in range(route):
        if G in D:
            return route*i+D[G]
        G *= C
        G %= P
    else:
        return -1

・DSU on Tree
@bootstrap
def get_size(n, p):
    for v in G[n]:
        if v == p:
            continue
        yield get_size(v, n)
        size[n] += size[v]
    yield

size = [1]*N
get_size(0, -1)

@bootstrap
def dfs(n, p, keep):
    MAX, bigv = -1, -1
    for v in G[n]:
        if v == p:
            continue
        if MAX < size[v]:
            MAX = size[v]
            bigv = v
    for v in G[n]:
        if v == p or v == bigv:
            continue
        yield dfs(v, n, 0)
    if bigv != -1:
        yield dfs(bigv, n, 1)
        A[n] = A[bigv]
    for v in G[n]:
        if v == p or v == bigv:
            continue
        for x in A[v]:
            A[n].append(x)
    A[n].append(n)
    if keep == 0:
        for v in A[n]:
            pass
    yield

A = [[] for _ in range(N)]
dfs(0, -1, 0)

・Suffix Automaton
class SuffixAutomaton:
    class Node:
        def __init__(self, nex, link, size):
            self.nex = nex
            self.link = link
            self.size = size
    def __init__(self, type):
        self.nodes = [self.Node([-1]*26, -1, 0)]
        self.ord_a = ord("a") if not type else ord("A")
        self.last = 0
    
    def alpha_code(self, s):
        return ord(s)-self.ord_a
    
    def push(self, c):
        new_node = len(self.nodes)
        code = self.alpha_code(c)
        self.nodes.append(self.Node([-1]*26, -1, self.nodes[self.last].size+1))
        p = self.last
        while p != -1 and self.nodes[p].nex[code] == -1:
            self.nodes[p].nex[code] = new_node
            p = self.nodes[p].link
        q = 0 if p == -1 else self.nodes[p].nex[code]
        if p == -1 or self.nodes[p].size+1 == self.nodes[q].size:
            self.nodes[new_node].link = q
        else:
            new_q = len(self.nodes)
            self.nodes.append(self.Node(self.nodes[q].nex[:], self.nodes[q].link, self.nodes[p].size+1))
            self.nodes[q].link = new_q
            self.nodes[new_node].link = new_q
            while p != -1 and self.nodes[p].nex[code] == q:
                self.nodes[p].nex[code] = new_q
                p = self.nodes[p].link
        self.last = new_node

・SkewHeap
class SkewHeap:
    class Node:
        __slots__ = ("key", "l", "r")
        def __init__(self, key):
            self.key = key
            self.l = None
            self.r = None

    def __init__(self, isMin=True):
        self.isMin = isMin

    def _comp(self, x, y):
        if self.isMin:
            return x.key < y.key
        else:
            return x.key > y.key

    def meld(self, x, y):
        if not x or not y:
            return x if x else y
        if not self._comp(x, y):
            x, y = y, x
        x.l = self.meld(x.l, y)
        x.l, x.r = x.r, x.l
        return x

    def alloc(self, key):
        return self.Node(key)

    def push(self, x, key):
        return self.meld(x, self.alloc(key))

    def pop(self, x):
        return self.meld(x.l, x.r)

・SkewHeap(遅延加算付き)
class SkewHeap:
    class Node:
        __slots__ = ("key", "laz", "l", "r")
        def __init__(self, key):
            self.key = key
            self.laz = 0
            self.l = None
            self.r = None

    def __init__(self, isMin=True):
        self.isMin = isMin
    
    def _propagate(self, x):
        if x.laz == 0:
            return
        if x.l:
            x.l.laz += x.laz
        if x.r:
            x.r.laz += x.laz
        x.key += x.laz
        x.laz = 0

    def _comp(self, x, y):
        if self.isMin:
            return x.key+x.laz < y.key+y.laz
        else:
            return x.key+x.laz > y.key+y.laz

    def meld(self, x, y):
        if not x or not y:
            return x if x else y
        if not self._comp(x, y):
            x, y = y, x
        self._propagate(x)
        x.l = self.meld(x.l, y)
        x.l, x.r = x.r, x.l
        return x

    def alloc(self, key):
        return self.Node(key)

    def push(self, x, key):
        return self.meld(x, self.alloc(key))

    def pop(self, x):
        self._propagate(x)
        return self.meld(x.l, x.r)
    
    def top(self, x):
        self._propagate(x)
        return x.key
    
    def apply(self, x, laz):
        x.laz += laz
        self._propagate(x)

・Cartesian Tree
def CartesianTree(P):
    stack = []
    child = [[-1]*2 for _ in range(N)]
    parent = [-1]*N
    for i in range(N):
        s = -1
        while stack and P[i] < P[stack[-1]]:
            s = stack.pop()
            child[i][0] = s
        if s != -1:
            parent[s] = i
        if stack:
            parent[i] = stack[-1]
            child[stack[-1]][1] = i
        stack.append(i)
    
    L, R = [-1]*N, [-1]*N
    stack = [(P.index(min(P)), 0, N-1)]
    while stack:
        n, l, r = stack.pop()
        L[n] = l
        R[n] = r
        a, b = child[n]
        if a != -1:
            stack.append((a, l, n-1))
        if b != -1:
            stack.append((b, n+1, r))
    return child, parent, L, R

・ラグランジュ補間(係数)
def lagrange_interpolation_coef(X, Y):
    N = len(X)-1
    for i in range(N+1):
        t = 1
        for j in range(N+1):
            if i != j:
                t *= X[i]-X[j]
                t %= MOD
        Y[i] *= inverse(1, t)
        Y[i] %= MOD

    dp = [0]*(N+2)
    dp[0] = 1
    for i in range(N+1):
        ndp = [0]*(N+2)
        for j in range(N+2):
            ndp[j] += dp[j]*(-X[i])%MOD
            ndp[j] %= MOD
            if 1 <= j:
                ndp[j] += dp[j-1]
                ndp[j] %= MOD
        dp = ndp

    ans = [0]*(N+1)
    invX = []
    for i in range(N+1):
        if X[i] != 0:
            invX.append(inverse(1, X[i]))
        else:
            invX.append(0)
    for i in range(N+1):
        if Y[i] == 0:
            continue
        if X[i] == 0:
            for j in range(N+1):
                ans[j] += dp[j+1]*Y[i]%MOD
                ans[j] %= MOD
        else:
            ans[0] -= dp[0]*invX[i]%MOD*Y[i]%MOD
            ans[0] %= MOD
            pre = (-dp[0])*invX[i]%MOD
            for j in range(1, N+1):
                ans[j] -= (dp[j]-pre)*invX[i]%MOD*Y[i]%MOD
                ans[j] %= MOD
                pre = ((-(dp[j]-pre))*invX[i])%MOD
    return ans

・ラグランジュ補間
def lagrange_interpolation(X, Y, T):
    N = len(X)-1
    ans = 0
    for i in range(N+1):
        t = 1
        t_inv = 1
        for j in range(N+1):
            if i == j:
                continue
            t *= T-X[j]
            t %= MOD
            t_inv *= X[i]-X[j]
            t_inv %= MOD
        ans += inverse(t, t_inv)*Y[i]%MOD
        ans %= MOD
    return ans

・ラグランジュ補間(等差数列)
def lagrange_interpolation_arithmetic(a, d, Y, T):
    # a = Xの初項 d = Xの交差
    N = len(Y)-1
    ans = 0
    ft = 1
    for i in range(N+1):
        ft *= (T-(a+d*i))%MOD
        ft %= MOD
    f = 1
    for i in range(1, N+1):
        f *= -i*d%MOD
        f %= MOD
    ans += inverse(Y[0]*ft%MOD, f*(T-a)%MOD)
    ans %= MOD
    for i in range(N):
        f *= inverse(d*(i+1), d*(i-N))
        f %= MOD
        ans += inverse(Y[i+1]*ft%MOD, f*(T-a-d*(i+1))%MOD)
        ans %= MOD
    return ans

・FPS
# https://github.com/atcoder/ac-library/blob/master/atcoder/convolution.hpp
from array import array

MOD = 998244353
IMAG = 911660635
IIMAG = 86583718
INV2 = 499122177
rate2 = array(
    "I",
    [
        0,
        911660635,
        509520358,
        369330050,
        332049552,
        983190778,
        123842337,
        238493703,
        975955924,
        603855026,
        856644456,
        131300601,
        842657263,
        730768835,
        942482514,
        806263778,
        151565301,
        510815449,
        503497456,
        743006876,
        741047443,
        56250497,
        867605899,
        0,
    ],
)
irate2 = array(
    "I",
    [
        0,
        86583718,
        372528824,
        373294451,
        645684063,
        112220581,
        692852209,
        155456985,
        797128860,
        90816748,
        860285882,
        927414960,
        354738543,
        109331171,
        293255632,
        535113200,
        308540755,
        121186627,
        608385704,
        438932459,
        359477183,
        824071951,
        103369235,
        0,
    ],
)
rate3 = array(
    "I",
    [
        0,
        372528824,
        337190230,
        454590761,
        816400692,
        578227951,
        180142363,
        83780245,
        6597683,
        70046822,
        623238099,
        183021267,
        402682409,
        631680428,
        344509872,
        689220186,
        365017329,
        774342554,
        729444058,
        102986190,
        128751033,
        395565204,
        0,
    ],
)
irate3 = array(
    "I",
    [
        0,
        509520358,
        929031873,
        170256584,
        839780419,
        282974284,
        395914482,
        444904435,
        72135471,
        638914820,
        66769500,
        771127074,
        985925487,
        262319669,
        262341272,
        625870173,
        768022760,
        859816005,
        914661783,
        430819711,
        272774365,
        530924681,
        0,
    ],
)


# https://judge.yosupo.jp/submission/55648
def butterfly(a: list):
    n = len(a)
    h = (n - 1).bit_length()
    le = 0
    while le < h:
        if h - le == 1:
            p = 1 << (h - le - 1)
            rot = 1
            for s in range(1 << le):
                offset = s << (h - le)
                for i in range(p):
                    l = a[i + offset]
                    r = a[i + offset + p] * rot
                    a[i + offset] = (l + r) % MOD
                    a[i + offset + p] = (l - r) % MOD
                rot *= rate2[(~s & -~s).bit_length()]
                rot %= MOD
            le += 1
        else:
            p = 1 << (h - le - 2)
            rot = 1
            for s in range(1 << le):
                rot2 = rot * rot % MOD
                rot3 = rot2 * rot % MOD
                offset = s << (h - le)
                for i in range(p):
                    a0 = a[i + offset]
                    a1 = a[i + offset + p] * rot
                    a2 = a[i + offset + p * 2] * rot2
                    a3 = a[i + offset + p * 3] * rot3
                    a1na3imag = (a1 - a3) % MOD * IMAG
                    a[i + offset] = (a0 + a2 + a1 + a3) % MOD
                    a[i + offset + p] = (a0 + a2 - a1 - a3) % MOD
                    a[i + offset + p * 2] = (a0 - a2 + a1na3imag) % MOD
                    a[i + offset + p * 3] = (a0 - a2 - a1na3imag) % MOD
                rot *= rate3[(~s & -~s).bit_length()]
                rot %= MOD
            le += 2


def butterfly_inv(a: list):
    n = len(a)
    h = (n - 1).bit_length()
    le = h
    while le:
        if le == 1:
            p = 1 << (h - le)
            irot = 1
            for s in range(1 << (le - 1)):
                offset = s << (h - le + 1)
                for i in range(p):
                    l = a[i + offset]
                    r = a[i + offset + p]
                    a[i + offset] = (l + r) % MOD
                    a[i + offset + p] = (l - r) * irot % MOD
                irot *= irate2[(~s & -~s).bit_length()]
                irot %= MOD
            le -= 1
        else:
            p = 1 << (h - le)
            irot = 1
            for s in range(1 << (le - 2)):
                irot2 = irot * irot % MOD
                irot3 = irot2 * irot % MOD
                offset = s << (h - le + 2)
                for i in range(p):
                    a0 = a[i + offset]
                    a1 = a[i + offset + p]
                    a2 = a[i + offset + p * 2]
                    a3 = a[i + offset + p * 3]
                    a2na3iimag = (a2 - a3) * IIMAG % MOD
                    a[i + offset] = (a0 + a1 + a2 + a3) % MOD
                    a[i + offset + p] = (a0 - a1 + a2na3iimag) * irot % MOD
                    a[i + offset + p * 2] = (a0 + a1 - a2 - a3) * irot2 % MOD
                    a[i + offset + p * 3] = (a0 - a1 - a2na3iimag) * irot3 % MOD
                irot *= irate3[(~s & -~s).bit_length()]
                irot %= MOD
            le -= 2


def intt(a):
    if len(a) <= 1:
        return
    butterfly_inv(a)
    iv = pow(len(a), MOD - 2, MOD)
    for i, x in enumerate(a):
        a[i] = x * iv % MOD


def multiply(s: list, t: list):
    n = len(s)
    m = len(t)
    if min(n, m) <= 60:
        a = [0] * (n + m - 1)
        for i in range(n):
            if i & 0b111 == 0:
                for j in range(m):
                    a[i + j] += s[i] * t[j]
                    a[i + j] %= MOD
            else:
                for j in range(m):
                    a[i + j] += s[i] * t[j]
        return [x % MOD for x in a]
    a = s.copy()
    b = t.copy()
    z = 1 << (n + m - 2).bit_length()
    a += [0] * (z - n)
    b += [0] * (z - m)
    butterfly(a)
    butterfly(b)
    for i in range(z):
        a[i] *= b[i]
        a[i] %= MOD
    butterfly_inv(a)
    a = a[: n + m - 1]
    iz = pow(z, MOD - 2, MOD)
    return [v * iz % MOD for v in a]


def pow2(s: list):
    n = len(s)
    l = (n << 1) - 1
    if n <= 60:
        a = [0] * l
        for i, x in enumerate(s):
            for j, y in enumerate(s):
                a[i + j] += x * y
        return [x % MOD for x in a]
    z = 1 << (l - 1).bit_length()
    a = s + [0] * (z - n)
    butterfly(a)
    for i, x in enumerate(a):
        a[i] = x * x % MOD
    butterfly_inv(a)
    a[l:] = []
    iz = pow(z, MOD - 2, MOD)
    return [x * iz % MOD for x in a]


def shrink(a: list):
    while a and not a[-1]:
        a.pop()


def fps_add(a: list, b: list):
    if len(a) < len(b):
        res = b.copy()
        for i, x in enumerate(a):
            res[i] += x
    else:
        res = a.copy()
        for i, x in enumerate(b):
            res[i] += x
    return [x - MOD if MOD <= x else x for x in res]


def fps_sub(a: list, b: list):
    if len(a) < len(b):
        res = b.copy()
        for i, x in enumerate(a):
            res[i] -= x
        return [MOD - x if 0 < x else -x for x in res]
    else:
        res = a.copy()
        for i, x in enumerate(b):
            res[i] -= x
        return [x if 0 <= x else x + MOD for x in res]


def fps_neg(a: list):
    return [MOD - x if x else 0 for x in a]


def fps_div(a: list, b: list) -> list:
    if len(a) < len(b):
        return []
    n = len(a) - len(b) + 1
    cnt = 0
    if len(b) > 64:
        return multiply(a[::-1][:n], fps_inv(b[::-1], n))[:n][::-1]
    f = a.copy()
    g = b.copy()
    while g and not g[-1]:
        g.pop()
        cnt += 1
    coef = pow(g[-1], MOD - 2, MOD)
    g = [x * coef % MOD for x in g]
    deg = len(f) - len(g) + 1
    lg = len(g)
    res = [0] * deg
    for i in reversed(range(deg)):
        res[i] = x = f[i + lg - 1] % MOD
        for j, y in enumerate(g):
            f[i + j] -= x * y
    return [x * coef % MOD for x in res] + [0] * cnt


def fps_mod(a: list, b: list) -> list:
    res = fps_sub(a, multiply(fps_div(a, b), b))
    while res and not res[-1]:
        res.pop()
    return res


def fps_divmod(a: list, b: list):
    q = fps_div(a, b)
    r = fps_sub(a, multiply(q, b))
    while r and not r[-1]:
        r.pop()
    return q, r


def fps_eval(a: list, x: int) -> int:
    r = 0
    w = 1
    for v in a:
        r += w * v % MOD
        w = w * x % MOD
    return r % MOD


def fps_inv(a: list, deg: int = -1):
    # assert(self[0] != 0)
    if deg == -1:
        deg = len(a)
    res = [0] * deg
    res[0] = pow(a[0], MOD - 2, MOD)
    d = 1
    iv = INV2
    while d < deg:
        d2 = d << 1
        f = [0] * d2
        fl = min(len(a), d2)
        f[:fl] = a[:fl]
        g = [0] * d2
        g[:d] = res[:d]
        butterfly(g)
        butterfly(f)
        for i in range(d2):
            f[i] = f[i] * g[i] % MOD
        butterfly_inv(f)
        f[:d] = [0] * d
        for i in range(d, d2):
            f[i] = f[i] * iv % MOD
        butterfly(f)
        for i in range(d2):
            f[i] = f[i] * g[i] % MOD
        butterfly_inv(f)
        for i in range(d, min(d2, deg)):
            res[i] = (MOD - f[i]) * iv % MOD
        d <<= 1
        iv = iv * INV2 % MOD
    return res


def fps_pow(a: list, k: int, deg=-1) -> list:
    n = len(a)
    if deg == -1:
        deg = n
    if k == 0:
        if not deg:
            return []
        res = [0] * deg
        res[0] = 1
        return res
    for i, x in enumerate(a):
        if x:
            iz = pow(x, MOD - 2, MOD)
            res = [x * iz % MOD for x in a[i:]]
            res = fps_log(res, deg)
            res = [x * k % MOD for x in res]
            res = fps_exp(res, deg)
            coef = pow(x, k, MOD)
            res = [0] * (i * k) + [x * coef % MOD for x in res]
            if len(res) < deg:
                return res + [0] * (deg - len(res))
            return res[:deg]
        if (i + 1) * k >= deg:
            break
    return [0] * deg


def fps_exp(a: list, deg: int = -1):
    # assert a[0] == 0
    if deg == -1:
        deg = len(a)
    inv = [0, 1]

    def inplace_integral(f: list) -> list:
        n = len(f)
        while len(inv) <= n:
            j, k = divmod(MOD, len(inv))
            inv.append((-inv[k] * j) % MOD)
        return [0] + [x * inv[i + 1] % MOD for i, x in enumerate(f)]

    b = [1, (a[1] if 1 < len(a) else 0)]
    c = [1]
    z1 = []
    z2 = [1, 1]
    m = 2
    while m < deg:
        y = b + [0] * m
        butterfly(y)
        z1 = z2
        z = [y[i] * p % MOD for i, p in enumerate(z1)]
        intt(z)
        z[: m >> 1] = [0] * (m >> 1)
        butterfly(z)
        for i, p in enumerate(z1):
            z[i] = z[i] * (-p) % MOD
        intt(z)
        c[m >> 1 :] = z[m >> 1 :]
        z2 = c + [0] * m
        butterfly(z2)
        tmp = min(len(a), m)
        x = a[:tmp] + [0] * (m - tmp)
        x = fps_diff(x)
        x.append(0)
        butterfly(x)
        for i, p in enumerate(x):
            x[i] = y[i] * p % MOD
        intt(x)
        for i, p in enumerate(b):
            if not i:
                continue
            x[i - 1] -= p * i % MOD
        x += [0] * m
        for i in range(m - 1):
            x[m + i], x[i] = x[i], 0
        butterfly(x)
        for i, p in enumerate(z2):
            x[i] = x[i] * p % MOD
        intt(x)
        x.pop()
        x = inplace_integral(x)
        x[:m] = [0] * m
        for i in range(m, min(len(a), m << 1)):
            x[i] += a[i]
        butterfly(x)
        for i, p in enumerate(y):
            x[i] = x[i] * p % MOD
        intt(x)
        b[m:] = x[m:]
        m <<= 1
    return b[:deg]


def fps_log(a: list, deg=-1) -> list:
    # assert(a[0] == 1)
    if deg == -1:
        deg = len(a)
    return fps_integral(multiply(fps_diff(a), fps_inv(a, deg))[: deg - 1])


def fps_integral(a: list):
    n = len(a)
    res = [0] * (n + 1)
    if n:
        res[1] = 1
    for i in range(2, n + 1):
        j, k = divmod(MOD, i)
        res[i] = (-res[k] * j) % MOD
    for i, x in enumerate(a):
        res[i + 1] = res[i + 1] * x % MOD
    return res


def fps_diff(a: list):
    return [i * x % MOD for i, x in enumerate(a) if i]


def LinearRecurrence(n: int, p: list, q: list):
    """
    [x^n]P(x)/Q(x)
    """
    # assert len(p) < len(q)
    shrink(q)
    while n:
        q2 = q[:]
        for i in range(1, len(q2), 2):
            q2[i] = (-q2[i]) % MOD
        s = multiply(p, q2)
        t = multiply(q, q2)
        for i in range(n & 1, len(s), 2):
            p[i >> 1] = s[i]
        for i in range(0, len(t), 2):
            q[i >> 1] = t[i]
        n >>= 1
    return p[0] * pow(q[0], -1, MOD) % MOD


def fps_compsite(f: list, g: list):
    """
    g(f(x)) mod x^(n+1)
    """

    # assert len(f) == len(g)
    def trans_multiply(s, t):
        n = len(s)
        m = len(t)
        l = 1 << (max(n, m) - 1).bit_length()
        a = s + [0] * (l - n)
        b = t + [0] * (l - m)
        a = [a[0]] + [a[l - i] for i in range(1, l)]
        butterfly(a)
        butterfly(b)
        iz = pow(l, MOD - 2, MOD)
        for i, x in enumerate(b):
            a[i] = a[i] * x % MOD * iz % MOD
        butterfly_inv(a)
        a = [a[0]] + [a[l - i] for i in range(1, l)]
        return a[: n - m + 1]

    n = len(f)
    l = 1 << (n - 1).bit_length()
    a = [MOD - x for x in f] + [0] * (2 * l - n)
    b = g + [0] * (l - n)

    def _inner(q, n, k):
        if n == 1:
            p = [0] * (2 * k)
            p[0::2] = b[::-1]
            return p
        siz = 2 * n * k
        r = [MOD - x if i & 1 else x for i, x in enumerate(q)]
        qq = multiply(q, r)
        qq.append(0)
        for i in range(0, siz, 2):
            qq[siz + i] = (qq[siz + i] + 2 * q[i]) % MOD
        nq = [0] * siz
        for j in range(2 * k):
            for i in range(n >> 1):
                nq[n * j + i] = qq[2 * n * j + 2 * i]
        np = _inner(nq, n >> 1, k << 1)

        pq = [0] * (2 * siz)
        for j in range(2 * k):
            for i in range(n >> 1):
                pq[2 * n * j + 2 * i + 1] = np[n * j + i]

        p = [pq[siz + i] for i in range(siz)]
        pq.pop()
        x = trans_multiply(pq, r)
        p = [(p[i] + x[i]) % MOD for i in range(siz)]
        return p

    p = _inner(a, l, 1)
    p = p[l - 1 :: -1]
    return p[:n]


def fps_compsitional_inv(calc, deg):
    """
    input
    calc(g, d) = f(g(x)) mod x^d を計算する
    fps_compsite よりも良い計算量のものが存在するならば書く

    output
    g(x) mod x^deg s.t. f(g(x)) = x
    """
    c = deg.bit_length()
    g = calc([0, 1], 2)
    g[1] = pow(g[1], -1, MOD)
    d = 2
    for i in range(c):
        d <<= 1
        fg = calc(g, d + 1)
        fdg = multiply(fps_diff(fg), fps_inv(fps_diff(g)))
        fdg[d:] = []
        fg[1] -= 1
        g = fps_sub(g, multiply(fg, fps_inv(fdg)))
        g[d:] = []
    g[deg:] = []
    return g


INVMOD = [1, 1]


def SubsetSum(d: list) -> list:
    """
    prod ( 1 + x^i ) ^ d[i]

    d[w] = 重さ w が d[w] 種類 1 個ずつある
    r[w] = 重さが w になるような選び方
    """
    n = len(d)
    for i in range(len(INVMOD), n):
        INVMOD.append(-INVMOD[MOD % i] * (MOD // i) % MOD)
    res = [0] * n
    sgn = [-1, 1]
    for i in range(1, n):
        if d[i]:
            tmp = d[i] * i
            for j in range(i, n, i):
                res[j] += tmp * INVMOD[j] * sgn[(j // i) & 1] % MOD
    res = fps_exp(res, n)
    return res


def MultisetSum(d: list) -> list:
    """
    prod ( 1 / ( 1 - x^i ) ) ^ d[i]

    d[w] = 重さ w が d[w] 種類 inf 個ずつある
    r[w] = 重さが w になるような選び方
    """
    n = len(d)
    for i in range(len(INVMOD), n):
        INVMOD.append(-INVMOD[MOD % i] * (MOD // i) % MOD)
    res = [0] * n
    for i in range(1, n):
        if d[i]:
            tmp = d[i] * i
            for j in range(i, n, i):
                res[j] += tmp * INVMOD[j] % MOD
    res = fps_exp(res, n)
    return res


fac = [1, 1]
finv = [1, 1]


def tayler_shift(a: list, c: int) -> list:
    global fac, finv
    n = len(a)
    l = len(fac)
    fac += [0] * (n - l)
    finv += [0] * (n - l)
    for i in range(l, n):
        fac[i] = fac[i - 1] * i % MOD
    finv[n - 1] = pow(fac[n - 1], MOD - 2, MOD)
    for i in reversed(range(l, n - 1)):
        finv[i] = finv[i + 1] * (i + 1) % MOD

    r = [x * fac[i] % MOD for i, x in enumerate(a)]
    b = [0] * n
    b[0] = 1
    for i in range(1, n):
        b[i] = b[i - 1] * c % MOD * finv[i] % MOD * fac[i - 1] % MOD
    r.reverse()
    res = multiply(r, b)[:n]
    return [x * finv[i] % MOD for i, x in enumerate(reversed(res))]


def _fft2d(s: list[list]):
    h, w = len(s), len(s[0])
    for i in range(h):
        butterfly(s[i])
    buf = [0] * h
    for j in range(w):
        buf = [s[i][j] for i in range(h)]
        butterfly(buf)
        for i in range(h):
            s[i][j] = buf[i]


def _ifft2d(s: list[list]):
    h, w = len(s), len(s[0])
    buf = [0] * h
    for j in range(w):
        buf = [s[i][j] for i in range(h)]
        intt(buf)
        for i in range(h):
            s[i][j] = buf[i]
    for i in range(h):
        intt(s[i])


def multiply_2D(s: list[list], t: list[list]):
    """
    not verify
    """
    from copy import deepcopy

    hs, ws = len(s), len(s[0])
    ht, wt = len(t), len(t[0])
    h = 1 << (hs + ht - 2).bit_length()
    w = 1 << (ws + wt - 2).bit_length()
    a = deepcopy(s)
    b = deepcopy(t)
    for i in range(hs):
        a[i] += [0] * (w - ws)
    for i in range(ht):
        b[i] += [0] * (w - wt)
    a += [[0] * w for i in range(h - hs)]
    b += [[0] * w for i in range(h - ht)]
    _fft2d(a)
    _fft2d(b)
    for i in range(h):
        for j in range(w):
            a[i][j] *= b[i][j]
            a[i][j] %= MOD
    _ifft2d(a)
    a = a[: hs + ht - 1]
    for i in range(hs + ht - 1):
        a[i][ws + wt - 1 :] = []
    return a

・Bostan-Mori法
# https://atcoder.jp/contests/tdpc/submissions/29624177
CONV = FFT(MOD)
def Bostan_Mori(P,Q,N):
    """
    [x^n] P(x)/Q(x) を d^2 log N ないし d log d log N で求める
    """
    if N==0:
        return P[0]
    Q2=[]
    for i in range(len(Q)):
        if i%2:Q2.append(-Q[i])
        else:Q2.append(Q[i])
    V=CONV.convolution(Q,Q2)[::2]
    if N%2:return Bostan_Mori(CONV.convolution(P,Q2)[1::2],V,N//2)
    else:return Bostan_Mori(CONV.convolution(P,Q2)[::2],V,N//2)

・階乗
def factorial(n):
    F = [1]
    for i in range(1, n+1):
        F.append(F[-1]*i%MOD)
    invF = [pow(F[-1], -1, MOD)]
    for i in reversed(range(n)):
        invF.append(invF[-1]*(i+1)%MOD)
    invF = invF[::-1]
    return F, invF

・グラフ ランダム生成
def gen_connected_graph(N, M, rng):
    assert M >= N-1
    edges = []
    used = set()

    # まず木を作る
    for i in range(1, N):
        p = rng.randint(0, i-1)
        u, v = min(p, i), max(p, i)
        edges.append((u, v))
        used.add((u, v))

    # 残りの辺をランダム追加
    while len(edges) < M:
        u = rng.randint(0, N-1)
        v = rng.randint(0, N-1)
        if u == v:
            continue
        u, v = min(u, v), max(u, v)
        if (u, v) in used:
            continue
        edges.append((u, v))
        used.add((u, v))

    return edges

・UnionFind(左右を管理)
class UnionFind:
    def __init__(self, n):
        self.n = n
        self.parent_size = [-1]*n
        self.L = list(range(n))
        self.R = list(range(n))
 
    def leader(self, a):
        if self.parent_size[a] < 0:
            return a
        self.parent_size[a] = self.leader(self.parent_size[a])
        return self.parent_size[a]
 
    def merge(self, a, b):
        x, y = self.leader(a), self.leader(b)
        if x == y:
            return 
        if abs(self.parent_size[x]) < abs(self.parent_size[y]):
            x, y = y, x
        self.parent_size[x] += self.parent_size[y]
        self.parent_size[y] = x
        self.L[x] = min(self.L[x], self.L[y])
        self.R[x] = max(self.R[x], self.R[y])
        return 
    
    def left(self, n):
        return self.L[self.leader(n)]
    
    def right(self, n):
        return self.R[self.leader(n)]
 
    def same(self, a, b):
        return self.leader(a) == self.leader(b)
 
    def size(self, a):
        return abs(self.parent_size[self.leader(a)])
 
    def groups(self):
        result = [[] for _ in range(self.n)]
        for i in range(self.n):
            result[self.leader(i)].append(i)
        return [r for r in result if r != []]

・行列式
def det(A):
    ans = 1
    N = len(A)
    sign = 1
    for i in range(N):
        pivot = i
        while pivot < N and A[pivot][i] == 0:
            pivot += 1
        if pivot == N:
            return 0
        
        if pivot != i:
            A[i], A[pivot] = A[pivot], A[i]
            sign *= -1
        
        inv = pow(A[i][i], -1, MOD)
        
        for j in range(i+1, N):
            factor = A[j][i]*inv%MOD
            for k in range(i, N):
                A[j][k] = (A[j][k]-factor*A[i][k])%MOD
        
        ans *= A[i][i]
        ans %= MOD
    
    ans *= sign
    ans %= MOD
    return ans

・最小共通祖先(重み付き)
class LCA:
    def __init__(self, G, root=0):
        V = len(G)
        self.bit_length = 1
        while 1<<self.bit_length < V:
            self.bit_length += 1
        self.parent = [[-1]*V for _ in range(self.bit_length)]
        self.depth = [-1]*V
        self.depth2 = [-1]*V
        self.bfs(G, root)
        for i in range(self.bit_length-1):
            for j in range(V):
                if self.parent[i][j] != -1:
                    self.parent[i+1][j] = self.parent[i][self.parent[i][j]]
        
    def bfs(self, G, root):
        self.depth[root] = 0
        que = deque()
        que.append(root)
        while que:
            n = que.popleft()
            for v, w in G[n]:
                if self.depth[v] == -1:
                    self.depth[v] = self.depth[n]+1
                    self.depth2[v] = self.depth2[n]+w
                    self.parent[0][v] = n
                    que.append(v)
    
    def lca(self, a, b):
        if self.depth[a] < self.depth[b]:
            a, b = b, a
        for i in range(self.bit_length):
            if (self.depth[a]-self.depth[b]) & 1<<i:
                a = self.parent[i][a]
        if a == b:
            return a
        for i in reversed(range(self.bit_length)):
            if self.parent[i][a] != self.parent[i][b]:
                a = self.parent[i][a]
                b = self.parent[i][b]
        return self.parent[0][a]
    
    def dist(self, a, b):
        return self.depth[a]+self.depth[b]-self.depth[self.lca(a, b)]*2
    
    def dist2(self, a, b):
        return self.depth2[a]+self.depth2[b]-self.depth2[self.lca(a, b)]*2
    
    def is_ancestor(self, u, v):
        return self.lca(u, v) == u
    
    def kth_ancestor(self, n, k):
        for i in range(self.bit_length):
            if 1<<i & k:
                n = self.parent[i][n]
                if n == -1:
                    break
        return n
    
    def jump(self, u, v):
        if u == v:
            return u
        if self.lca(u, v) == u:
            return self.kth_ancestor(v, self.dist(u, v)-1)
        else:
            return self.parent[0][u]
    
    def jump_k(self, u, v, k):
        d = self.dist(u, v)
        if d <= k:
            return v
        lca = self.lca(u, v)
        if k <= self.depth[u]-self.depth[lca]:
            return self.kth_ancestor(u, k)
        else:
            return self.kth_ancestor(v, d-k)
    
    def on_path(self, u, v, x):
        return self.dist(u, x)+self.dist(x, v) == self.dist(u, v)

    def create_path(self, u, v, x):
        if self.on_path(u, v, x):
            return u, v
        if self.on_path(u, x, v):
            return u, x
        if self.on_path(v, x, u):
            return v, x
        return -1, -1

・(重み付き)AuxiliaryTree
class AuxiliaryTree:
    def __init__(self, N, G):
        self.N = N
        self.G = G
        self.IN = [0]*N
        self.OUT = [0]*N
        self.depth = [0]*N
        self.depth2 = [0]*N
        self.E = []
        self.dfs(0, -1, 0, 0)
        self.L = len(self.E)
        self.lg = [0]*(self.L+1)
        self.make_sparse_table()

    @bootstrap
    def dfs(self, n, p, d, d2):
        self.depth[n] = d
        self.depth2[n] = d2
        self.IN[n] = len(self.E)
        self.E.append(n)
        for v, w in self.G[n]:
            if v == p:
                continue
            yield self.dfs(v, n, d+1, d2+w)
            self.E.append(n)
        self.OUT[n] = len(self.E)
        self.E.append(n)
        yield
    
    def make_sparse_table(self):
        for i in range(2, self.L+1):
            self.lg[i] = self.lg[i>>1]+1
        self.st = [[self.L]*(self.L-(1<<i)+1) for i in range(self.lg[self.L]+1)]
        self.st[0] = self.E[:]
        b = 1
        for i in range(self.lg[self.L]):
            for j in range(self.L-(b<<1)+1):
                self.st[i+1][j] = (self.st[i][j] if self.depth[self.st[i][j]] <= self.depth[self.st[i][j+b]] else self.st[i][j+b])
            b <<= 1
    
    def lca(self, u, v):
        x, y = self.IN[u], self.IN[v]
        l = self.lg[y-x+1]
        return self.st[l][x] if self.depth[self.st[l][x]] <= self.depth[self.st[l][y-(1<<l)+1]] else self.st[l][y-(1<<l)+1]
    
    def query(self, v):
        nG = defaultdict(list)
        V = v[:]
        V.sort(key=self.IN.__getitem__)
        K = len(V)
        stack = [V[0]]
        for i in range(K-1):
            w = self.lca(V[i], V[i+1])
            if w != V[i]:
                last = stack.pop()
                while stack and self.depth[w] < self.depth[stack[-1]]:
                    d = abs(self.depth[stack[-1]]-self.depth[last])
                    d2 = abs(self.depth2[stack[-1]]-self.depth2[last])
                    nG[stack[-1]].append((last, d, d2))
                    nG[last].append((stack[-1], d, d2))
                    last = stack.pop()
                if not stack or stack[-1] != w:
                    stack.append(w)
                    V.append(w)
                d = abs(self.depth[w]-self.depth[last])
                d2 = abs(self.depth2[w]-self.depth2[last])
                nG[w].append((last, d, d2))
                nG[last].append((w, d, d2))
            stack.append(V[i+1])
        for i in range(len(stack)-1):
            d = abs(self.depth[stack[i]]-self.depth[stack[i+1]])
            d2 = abs(self.depth2[stack[i]]-self.depth2[stack[i+1]])
            nG[stack[i]].append((stack[i+1], d, d2))
            nG[stack[i+1]].append((stack[i], d, d2))
        return nG, stack[0]

・Aho-Corasick
class AhoCorasick:
    def __init__(self, type):
        self.next = [[-1]*26]
        self.link = [-1]
        self.out = [[]]
        self.size = 1
        self.base = ord("a") if type == 0 else ord("A")
    
    def code(self, s):
        return ord(s)-self.base

    def add_word(self, word, idx):
        v = 0
        for c in word:
            if self.next[v][self.code(c)] == -1:
                self.next[v][self.code(c)] = self.size
                self.next.append([-1]*26)
                self.link.append(0)
                self.out.append([])
                self.size += 1
            v = self.next[v][self.code(c)]
        self.out[v].append(idx)

    def build(self):
        que = deque()
        for i in range(26):
            if self.next[0][i] != -1:
                self.link[self.next[0][i]] = 0
                que.append(self.next[0][i])
        while que:
            n = que.popleft()
            for i in range(26):
                if self.next[n][i] != -1:
                    f = self.link[n]
                    while f != -1 and self.next[f][i] == -1:
                        f = self.link[f]
                    if f == -1:
                        self.link[self.next[n][i]] = 0
                    else:
                        self.link[self.next[n][i]] = self.next[f][i]
                    self.out[self.next[n][i]].extend(self.out[self.link[self.next[n][i]]])
                    que.append(self.next[n][i])

    def match(self, text):
        res = []
        n = 0
        for i, c in enumerate(text):
            while n != 0 and self.next[n][self.code(c)] == -1:
                n = self.link[n]
            if self.next[n][self.code(c)] != -1:
                n = self.next[n][self.code(c)]
            for idx in self.out[n]:
                res.append((i, idx))
        return res
    
    def go(self, idx, s):
        while 1 <= idx and self.next[idx][self.code(s)] == -1:
            idx = self.link[idx]
        return self.next[idx][self.code(s)] if self.next[idx][self.code(s)] != -1 else 0

・BIT(MOD)
class BIT:
    def __init__(self, A):
        self.size = len(A)
        self.bit = [0]*(len(A)+1)
        for i in range(len(A)):
            self.add(i, A[i])

    def sum(self, i):
        i += 1
        ans = 0
        while i > 0:
            ans += self.bit[i]
            ans %= MOD
            i -= -i&i
        return ans
    
    def query(self, l, r):
        if l == 0:
            return self.sum(r-1)
        else:
            return (self.sum(r-1)-self.sum(l-1))%MOD
    
    def add(self, i, x):
        i += 1
        while i <= self.size:
            self.bit[i] += x
            self.bit[i] %= MOD
            i += -i&i

・オフラインrangefreq
def offline_range_freq_to(A, query):
    N = len(A)
    Q = len(query)

    A = sorted(enumerate(A), key=lambda x:x[1])
    query = sorted(enumerate(query), key=lambda x:x[1][2])

    F = BIT([0]*N)
    ans = [-1]*Q
    idx = 0
    for qidx, (l, r, x) in query:
        while idx < N and A[idx][1] <= x:
            F.add(A[idx][0], 1)
            idx += 1
        ans[qidx] = F.query(l, r+1)
    return ans

def offline_range_freq_from(A, query):
    N = len(A)
    Q = len(query)

    A = sorted(enumerate(A), key=lambda x:x[1], reverse=True)
    query = sorted(enumerate(query), key=lambda x:x[1][2], reverse=True)

    F = BIT([0]*N)
    ans = [-1]*Q
    idx = 0
    for qidx, (l, r, x) in query:
        while idx < N and x <= A[idx][1]:
            F.add(A[idx][0], 1)
            idx += 1
        ans[qidx] = F.query(l, r+1)
    return ans

・Codonテンプレート
#generatorに__getitem__, __contains__を定義
@extend
class Generator:
    def __getitem__(self: Generator[T], _: int) -> T:
        if self.done(): raise StopIteration()
        return self.next()
    def __getitem__(self: Generator[T], key: slice) -> list[T]:
        assert key.stop is None, (
            '''本拡張では、末尾以外でのアンパッキングはできません。
            例として、 N, *A = generator には対応しますが *A, N = generator は非対応です。
            右辺の generator を list(generator) と書き換えてみてください。''')
        return list(self)
    def __contains__(self: Generator[T], key: T) -> bool:
        return key in list(self)

#int同士の除算結果をPythonの負の無限大丸めに合わせる
@extend
class int:
    @pure
    @llvm
    def _floordiv_int_int(self: int, other: int) -> int:
        %0 = sdiv i64 %self, %other
        ret i64 %0
    @overload
    def __floordiv__(self, other: int):
        d = self._floordiv_int_int(other)
        m = self - d * other
        if m and ((other ^ m) < 0):
            d -= 1
        return d
    @pure
    @llvm
    def _mod_int_int(self: int, other: int) -> int:
        %0 = srem i64 %self, %other
        ret i64 %0
    @overload
    def __mod__(self, other: int) -> int:
        m = self._mod_int_int(other)
        if m and ((other ^ m) < 0):
            m += other
        return m

#int.bit_length, int.bit_countに対応
@extend
class int:
    def bit_length(self): 
        return 64 - abs(self).__ctlz__()
    def bit_count(self):
        return abs(self).__ctpop__()

#int hash値をSplitMix64で変更する
#Reference: https://prng.di.unimi.it/splitmix64.c
@extend
class int:
    def __hash__(self) -> int:
        z: UInt[64] = UInt[64](self) + UInt[64](0x9e3779b97f4a7c15)
        z = (z ^ (z >> UInt[64](30))) * UInt[64](0xbf58476d1ce4e5b9)
        z = (z ^ (z >> UInt[64](27))) * UInt[64](0x94d049bb133111eb)
        return int(z ^ (z >> UInt[64](31)))

#floatの出力桁数を15桁に増やす
@extend
class float:
    def __str__(self): return f'{self:15f}'

#巨大mod時のオーバーフローを回避  pow(base, -1, mod)に対応
def _extended_pow():
    _builtin_pow = pow
    def _codon_pow(base, exp):
        return _builtin_pow(base, exp)
    @overload
    def _codon_pow(base: int, exp: int, mod: int) -> int:
        '''
        codon用に pow(base, exp, mod) を拡張した関数です。
        1. (abs(mod) - 1) ** 2 >= 1 << 63 の場合に発生していたオーバーフローを回避しました。
        2. pow(base: int, exp: 負整数, mod: int) による逆元計算に対応しました。

        返り値の符号は mod の符号に一致します。
        いずれかの引数に INF_MIN := -1 << 63 を渡した場合の動作は未定義です。
        '''
        if mod == 0:
            raise ValueError('pow() 3rd argument cannot be 0')
        if mod == 1 or mod == -1:
            return 0
        if exp < 0:  #拡張ユークリッドの互除法
            a, b, x, y = base, mod, 1, 0
            while b:
                q = a // b
                a, b, x, y = b, a - q * b, y, x - q * y
            if a != 1 and a != -1:
                raise ValueError('base is not invertible for the given modulus')
            b128, m128 = Int[128](x), Int[128](mod)
            if a == -1:
                b128 = - b128
            exp = - exp
        else:
            b128, m128 = Int[128](base), Int[128](mod)
        v128 = Int[128](1)
        while exp:
            if exp & 1 == 1:
                v128 = v128 * b128 % m128
            b128 = b128 * b128 % m128
            exp >>= 1
        v = int(v128)
        return v + mod if v != 0 and (0 < v) != (0 < mod) else v
    return _codon_pow
pow = _extended_pow()

・スライド最小値(最大値)
class MonotonicQueue:
    def __init__(self, A, isMIN=True):
        self.N = len(A)
        self.A = A
        self.isMIN = isMIN
        self.que = deque()
        self.left = 0
        self.right = 0
    
    def _cmp(self, a, b):
        return a >= b if self.isMIN else a <= b
    
    def move_right(self):
        if self.right == self.N: return False
        while self.que and self._cmp(self.que[-1][0], self.A[self.right]):
            self.que.pop()
        self.que.append((self.A[self.right], self.right))
        self.right += 1
        return True

    def move_left(self):
        if self.left == self.right: return False
        if self.que[0][1] == self.left:
            self.que.popleft()
        self.left += 1
        return True
    
    def get(self):
        return self.que[0][0] if self.que else None

・オイラーグラフ判定
def isEulerGraph(G, isDirected = False):
    N = len(G)
    if not isDirected:
        cnt = [0]*N
        UF = UnionFind(N)
        for n in range(N):
            for v in G[n]:
                cnt[n] += 1
                UF.merge(n, v)
        odd = sum(cnt[i]%2 == 1 for i in range(N))
        cntE = sum(1 <= cnt[i] for i in range(N))
        if odd == 0:
            if 1 <= cntE:
                for i in range(N):
                    if 1 <= cnt[i]:
                        if UF.size(i) == cntE:
                            return True, True, i, -1
                        else:
                            return False, False, -1, -1
            else:
                return True, True, -1, -1
        elif odd == 2:
            l, r = -1, -1
            for i in range(N):
                if cnt[i]%2 == 1:
                    if l == -1:
                        l = i
                    else:
                        r = i
                        break
            if UF.size(l) == cntE:
                return True, False, l, r
            else:
                return False, False, -1, -1
        else:
            return False, False, -1, -1
    else:
        IN = [0]*N
        OUT = [0]*N
        UF = UnionFind(N)
        for n in range(N):
            for v in G[n]:
                OUT[n] += 1
                IN[v] += 1
                UF.merge(n, v)
        s, g = -1, -1
        m = -1
        cntE = sum(1 <= IN[i]+OUT[i] for i in range(N))
        for i in range(N):
            if IN[i]+1 == OUT[i]:
                if s == -1:
                    s = i
                else:
                    return False, False, -1, -1
            elif OUT[i]+1 == IN[i]:
                if g == -1:
                    g = i
                else:
                    return False, False, -1, -1
            elif IN[i] != OUT[i]:
                return False, False, -1, -1
            if 1 <= IN[i]+OUT[i] and m == -1:
                m = i
        if m != -1 and UF.size(m) != cntE:
            return False, False, -1, -1
        if s == g == -1:
            return True, True, m, -1
        elif s != -1 and g != -1:
            return True, False, s, g
        else:
            return False, False, -1, -1

・二項係数の区間和
class rangeBinomial:
    def __init__(self, N, L, R):
        self.N = N
        self.L = L
        self.R = R
        self.val = 0
        for i in range(L, R+1):
            self.val += cp.C(N, i)
            self.val %= MOD
        self.half = pow(2, -1, MOD)
    
    def add(self):
        self.val *= 2
        self.val %= MOD
        self.val += cp.C(self.N, self.L-1)-cp.C(self.N, self.R)
        self.val %= MOD
        self.N += 1
        return True

    def sub(self):
        if self.N == 0:
            return False
        self.N -= 1
        self.val += cp.C(self.N, self.R)-cp.C(self.N, self.L-1)
        self.val %= MOD
        self.val *= self.half
        self.val %= MOD
        return True
    
    def move_ll(self):
        if self.L == 0:
            return False
        self.L -= 1
        self.val += cp.C(self.N, self.L)
        self.val %= MOD
        return True
    
    def move_lr(self):
        if self.L == self.R:
            return False
        self.val -= cp.C(self.N, self.L)
        self.val %= MOD
        self.L += 1
        return True
    
    def move_rr(self):
        self.R += 1
        self.val += cp.C(self.N, self.R)
        self.val %= MOD
        return True
    
    def move_rl(self):
        if self.L == self.R:
            return False
        self.val -= cp.C(self.N, self.R)
        self.val %= MOD
        self.R -= 1
        return True

    def get(self):
        return self.val

・円の交点
def circle_intersections(x1, y1, r1, x2, y2, r2):
    d = distance(x1, y1, x2, y2)
    dx = x2 - x1
    dy = y2 - y1

    # 交点なし
    if d > r1 + r2 or d < abs(r1 - r2) or d == 0:
        return []

    a = (r1*r1 - r2*r2 + d*d) / (2*d)
    h_sq = r1*r1 - a*a
    if h_sq < 0:
        h_sq = 0
    h = h_sq**0.5

    x3 = x1 + a * dx / d
    y3 = y1 + a * dy / d

    rx = -dy * (h / d)
    ry = dx * (h / d)

    return [(x3 + rx, y3 + ry), (x3 - rx, y3 - ry)]

・2-SAT
class TwoSAT:
    def __init__(self, N):
        self.N = N
        self.edge = []
        self.solution = [False]*N
        self.solved = False
    
    def add_constraint(self, u, f, v, g):
        self.edge.append((u+self.N*f, v+self.N*g))

    def add_clause(self, u, f, v, g):
        self.add_constraint(u, f^True, v, g)
        self.add_constraint(v, g^True, u, f)
    
    def solve(self):
        SCC = scc(self.N*2, self.edge)
        order = [-1]*(self.N*2)
        for i, s in enumerate(SCC):
            for n in s:
                order[n] = i
        for i in range(self.N):
            if order[i] == order[i+self.N]:
                return False
            if order[i] > order[i+self.N]:
                self.solution[i] = False
            else:
                self.solution[i] = True
        self.solved = True
        return True
    
    def result(self):
        return self.solution if self.solved else None

・2-SAT(密グラフ)
class TwoSAT:
    def __init__(self, N, M):
        self.N = N
        self.M = M
        self.edge = []
        self.solution = [False]*self.N
        self.cnt = 0
        self.solved = False
    
    def add_constraint(self, u, f, v, g):
        self.edge.append((u+(self.N+self.M)*f, v+(self.N+self.M)*g))

    def add_clause(self, u, f, v, g):
        self.add_constraint(u, f^True, v, g)
        self.add_constraint(v, g^True, u, f)
    
    def add_at_most_one(self, A):
        for i in range(len(A)):
            self.add_clause(A[i][0], A[i][1], self.N+self.cnt+i, True)
            if i+1 < len(A):
                self.add_clause(self.N+self.cnt+i, False, self.N+self.cnt+i+1, True)
                self.add_clause(self.N+self.cnt+i, False, A[i+1][0], A[i+1][1])
        self.cnt += len(A)
    
    def solve(self):
        SCC = scc((self.N+self.M)*2, self.edge)
        order = [-1]*((self.N+self.M)*2)
        for i, s in enumerate(SCC):
            for n in s:
                order[n] = i
        for i in range(self.N):
            if order[i] == order[i+self.N+self.M]:
                return False
            if order[i] > order[i+self.N+self.M]:
                self.solution[i] = False
            else:
                self.solution[i] = True
        self.solved = True
        return True
    
    def result(self):
        return self.solution[:self.N] if self.solved else None

・Slope-Trick
from heapq import heappush, heappop

class SlopeTrick:
    def __init__(self):
        self.min_f = 0
        self.L = []
        self.R = []
        self.add_l = 0
        self.add_r = 0
    
    def push_R(self, a):
        heappush(self.R, a-self.add_r)
    
    def top_R(self):
        return self.R[0]+self.add_r if self.R else INF
    
    def pop_R(self):
        val = self.top_R()
        if self.R: heappop(self.R)
        return val
    
    def push_L(self, a):
        heappush(self.L, -(a-self.add_l))
    
    def top_L(self):
        return -self.L[0]+self.add_l if self.L else -INF
    
    def pop_L(self):
        val = self.top_L()
        if self.L: heappop(self.L)
        return val
    
    def size(self):
        return len(self.L)+len(self.R)
    
    def query(self):
        return self.top_L(), self.top_R(), self.min_f
    
    def add_all(self, a):
        self.min_f += a
    
    def add_x_minus_a(self, a):
        self.min_f += max(self.top_L()-a, 0)
        self.push_L(a)
        self.push_R(self.pop_L())

    def add_a_minus_x(self, a):
        self.min_f += max(a-self.top_R(), 0)
        self.push_R(a)
        self.push_L(self.pop_R())
    
    def add_abs(self, a):
        self.add_x_minus_a(a)
        self.add_a_minus_x(a)
    
    def clear_right(self):
        self.R = []

    def clear_left(self):
        self.L = []
    
    def shift2(self, a, b):
        self.add_l += a
        self.add_r += b
    
    def shift(self, a):
        self.shift2(a, a)
    
    def get(self, x):
        ret = self.min_f
        for l in self.L:
            n = -l+self.add_l
            ret += max(n-x, 0)
        for r in self.R:
            n = r+self.add_r
            ret += max(x-n, 0)
        return ret
    
    def merge(self, st):
        if self.size() < st.size():
            self.L, st.L = st.L, self.L
            self.R, st.R = st.R, self.R
            self.add_l, st.add_l = st.add_l, self.add_l
            self.add_r, st.add_r = st.add_r, self.add_r
            self.min_f, st.min_f = st.min_f, self.min_f
        while st.R:
            self.add_x_minus_a(st.pop_R())
        while st.L:
            self.add_a_minus_x(st.pop_L())
        self.min_f += st.min_f

・monotone minima
# select(i, j, k) AijとAikでAikを選ぶならTrue
def monotone_minima(H, W, select):
    def solve(row):
        L = len(row)
        if L == 0: return []
        row2 = [row[i] for i in range(L) if i%2 == 1]
        ans2 = solve(row2)
        ans = [0]*L
        for i in range(len(ans2)):
            ans[i*2+1] = ans2[i]
        idx = 0
        for i in range(0, L, 2):
            ans[i] = idx
            end = ans[i+1] if i+1 < L else W-1
            while idx != end:
                idx += 1
                if select(row[i], ans[i], idx): ans[i] = idx
        return ans
    return solve(list(range(H)))

・最大値(最小値)Top2
class Top2:
    def __init__(self):
        self.best1 = (-INF, -1)
        self.best2 = (-INF, -1)

    def add(self, val, genre):
        b1v, b1g = self.best1
        b2v, b2g = self.best2

        if genre == b1g:
            if val > b1v:
                self.best1 = (val, genre)
        else:
            if val > b1v:
                self.best2 = self.best1
                self.best1 = (val, genre)
            elif val > b2v:
                self.best2 = (val, genre)

    def get_exclude(self, genre):
        if self.best1[1] != genre:
            return self.best1[0]
        else:
            return self.best2[0]

・LCA(Sparse Table)
class LCA:
    def __init__(self, G, root=0):
        self.G = G
        self.N = len(G)
        self.A = []
        self.IN = [0]*self.N
        self.depth = [0]*self.N
        self.dfs(root, -1, 0)

        self.L = len(self.A)
        self.log = [0]*(self.L + 1)
        for i in range(2, self.L+1):
            self.log[i] = self.log[i >> 1] + 1
        self.sparse = [None]*(self.log[self.L] + 1)
        self.sparse[0] = self.A
        b = 1
        for i in range(self.log[self.L]):
            self.sparse[i+1] = [p if self.depth[p] <= self.depth[q] else q for p, q in zip(self.sparse[i], self.sparse[i][b:])]
            b <<= 1

    @bootstrap
    def dfs(self, n, p, d):
        self.depth[n] = d
        self.IN[n] = len(self.A)
        self.A.append(n)
        for v in self.G[n]:
            if v == p:
                continue
            yield self.dfs(v, n, d+1)
            self.A.append(n)
        yield
    
    def lca(self, u, v):
        l = self.IN[u]
        r = self.IN[v]
        if l > r:
            l, r = r, l
        k = self.log[r-l+1]
        a = self.sparse[k][l]
        b = self.sparse[k][r-(1<<k)+1]
        return a if self.depth[a] <= self.depth[b] else b
    
    def dist(self, a, b):
        return self.depth[a]+self.depth[b]-self.depth[self.lca(a, b)]*2

・XOR基底
class XORBasis:
    def __init__(self, A):
        self.A = A
        self.base = []
        self.mask = []
        self.IDX = []
        self.dependent = -1
        for i, a in enumerate(self.A):
            n = a
            xor = 1<<len(self.base)
            for j, b in enumerate(self.base):
                if n^b < n:
                    n ^= b
                    xor ^= self.mask[j]
            if n:
                self.IDX.append(i)
                self.base.append(n)
                self.mask.append(xor)
            elif self.dependent == -1:
                self.dependent = i
        if len(self.base) == 0:
            return
        pairs = sorted(zip(self.base, self.mask), key=lambda x:x[0], reverse=True)
        self.base, self.mask = map(list, zip(*pairs))
        for i in range(1, len(self.base)):
            for j in range(i):
                if self.base[j]^self.base[i] < self.base[j]:
                    self.base[j] ^= self.base[i]
                    self.mask[j] ^= self.mask[i]

    def can_make(self, x):
        for b in self.base:
            if 1<<(b.bit_length()-1) & x:
                x ^= b
        return x == 0

    def can_make_nonemptyzero(self):
        return self.dependent != -1

    def get_indices(self, x):
        xor = 0
        for i, b in enumerate(self.base):
            if 1<<(b.bit_length()-1) & x:
                x ^= b
                xor ^= self.mask[i]
        if x:
            return None
        ans = []
        for i in range(len(self.base)):
            if 1<<i & xor:
                ans.append(self.IDX[i])
        return ans

    def get_indices_nonemptyzero(self):
        if not self.can_make_nonemptyzero():
            return None
        return sorted(self.get_indices(self.A[self.dependent])+[self.dependent])

    def get_max(self, x = 0):
        for b in self.base:
            x = max(x, x^b)
        return x

    def get_min(self, x = 0):
        for b in self.base:
            x = min(x, x^b)
        return x

    def kth_min(self, k):
        if k < 0 or 1<<len(self.base) < k:
            return -1
        ans = 0
        for i, b in enumerate(self.base):
            if 1<<(len(self.base)-1-i) & k:
                ans ^= b
        return ans

    def kth_max(self, k):
        return self.kth_min((1<<len(self.base))-k)

・XOR畳み込み
def FWHT(A, inverse=False):
    N = len(A)

    H = 1
    while H < N:
        for i in range(0, N, H*2):
            for j in range(i, i+H):
                x = A[j]
                y = A[j+H]
                A[j] = (x+y)%MOD
                A[j+H] = (x-y)%MOD
        H *= 2

    if inverse:
        inv = pow(N, -1, MOD)
        for i in range(N):
            A[i] *= inv
            A[i] %= MOD

def xor_convolution(a, b):
    A = a[:]
    B = b[:]
    
    N = 1
    while N < max(len(A), len(B)):
        N *= 2
    A += [0]*(N-len(A))
    B += [0]*(N-len(B))

    FWHT(A)
    FWHT(B)

    for i in range(N):
        A[i] *= B[i]
        A[i] %= MOD

    FWHT(A, inverse=True)

    return A

・ランダムテスト
import subprocess
import sys
from random import randrange, shuffle

# 1.ファイル名を書き換える
SOL = ".py"
NAIVE = "_naive.py"
TEST_COUNT = 100
TIMEOUT_SECOND = 2

def generate():
    # 2.入力を作成する
    lines = []

    return "\n".join(lines)+"\n"

def prepare(filename):
    """
    実行するコマンドを返す。
    Pythonならそのまま。
    C++なら先にコンパイルする。
    """

    if filename.endswith(".py"):
        return [sys.executable, filename]

    if filename.endswith(".cpp"):
        exe = filename[:-4] + ".exe"

        result = subprocess.run(
            [
                "g++",
                filename,
                "-std=c++20",
                "-O2",
                "-o",
                exe,
            ],
            text=True,
            capture_output=True,
        )

        if result.returncode != 0:
            print(f"{filename} のコンパイルに失敗")
            print(result.stderr)
            exit()

        return [exe]

    raise ValueError(f"対応していないファイル形式: {filename}")

def run(command, test):
    try:
        result = subprocess.run(
            command,
            input=test,
            text=True,
            capture_output=True,
            timeout=TIMEOUT_SECOND,
        )
    except subprocess.TimeoutExpired:
        print("TLE!")
        print("command:", command)
        print("===== input =====")
        print(test, end="")
        exit()

    if result.returncode != 0:
        print("RE!")
        print("command:", command)
        print("===== input =====")
        print(test, end="")
        print("===== stderr =====")
        print(result.stderr)
        exit()

    return result.stdout.strip()

sol_command = prepare(SOL)
naive_command = prepare(NAIVE)

for t in range(TEST_COUNT):
    test = generate()

    ans1 = run(sol_command, test)
    ans2 = run(naive_command, test)

    if ans1 != ans2:
        print("WA")
        print("===== input =====")
        print(test, end="")
        print("===== solution =====")
        print(ans1)
        print("===== naive =====")
        print(ans2)

        with open("failed.txt", "w") as f:
            f.write(test)

        break
else:
    print("All tests passed!")

・ランダムテスト(小数誤差許容)
import subprocess
import sys
import math
from random import randrange, shuffle

# 1.ファイル名を書き換える
SOL = ".py"
NAIVE = "_naive.py"
TEST_COUNT = 100
TIMEOUT_SECOND = 2

# 2.許容誤差を設定する
ABS_EPS = 1e-6
REL_EPS = 1e-6

def generate():
    # 3.入力を作成する
    lines = []

    return "\n".join(lines)+"\n"

def prepare(filename):
    """
    実行するコマンドを返す。
    Pythonならそのまま。
    C++なら先にコンパイルする。
    """

    if filename.endswith(".py"):
        return [sys.executable, filename]

    if filename.endswith(".cpp"):
        exe = filename[:-4] + ".exe"

        result = subprocess.run(
            [
                "g++",
                filename,
                "-std=c++20",
                "-O2",
                "-o",
                exe,
            ],
            text=True,
            capture_output=True,
        )

        if result.returncode != 0:
            print(f"{filename} のコンパイルに失敗")
            print(result.stderr)
            exit()

        return [exe]

    raise ValueError(f"対応していないファイル形式: {filename}")

def run(command, test):
    try:
        result = subprocess.run(
            command,
            input=test,
            text=True,
            capture_output=True,
            timeout=TIMEOUT_SECOND,
        )
    except subprocess.TimeoutExpired:
        print("TLE!")
        print("command:", command)
        print("===== input =====")
        print(test, end="")
        exit()

    if result.returncode != 0:
        print("RE!")
        print("command:", command)
        print("===== input =====")
        print(test, end="")
        print("===== stderr =====")
        print(result.stderr)
        exit()

    return result.stdout.strip()

def compare(ans1, ans2):
    """
    空白区切りで比較する。

    数値なら誤差を許容。
    数値でないトークンは完全一致。
    """

    A = ans1.split()
    B = ans2.split()

    if len(A) != len(B):
        return False, f"出力トークン数が違う: {len(A)} != {len(B)}"

    for i, (a, b) in enumerate(zip(A, B)):
        try:
            x = float(a)
            y = float(b)

            if not math.isfinite(x) or not math.isfinite(y):
                return False, f"{i} 番目に非有限値がある: {a}, {b}"

            if not math.isclose(
                x,
                y,
                rel_tol=REL_EPS,
                abs_tol=ABS_EPS,
            ):
                return False, (
                    f"{i} 番目が誤差範囲外: "
                    f"{a} != {b}, diff = {abs(x-y)}"
                )

        except ValueError:
            # 数値でなければ文字列として比較
            if a != b:
                return False, f"{i} 番目が違う: {a} != {b}"

    return True, ""

sol_command = prepare(SOL)
naive_command = prepare(NAIVE)

for t in range(TEST_COUNT):
    test = generate()

    ans1 = run(sol_command, test)
    ans2 = run(naive_command, test)

    ok, reason = compare(ans1, ans2)

    if not ok:
        print("WA")
        print("===== input =====")
        print(test, end="")
        print("===== solution =====")
        print(ans1)
        print("===== naive =====")
        print(ans2)
        print("===== reason =====")
        print(reason)

        with open("failed.txt", "w") as f:
            f.write(test)

        break
else:
    print("All tests passed!")

・ランダムテスト(スペシャルジャッジ)
import subprocess
import sys
from random import randrange, shuffle

# 1.ファイル名を書き換える
SOL = ".py"
TEST_COUNT = 100
TIMEOUT_SECOND = 2

def generate():
    # 2.入力を作成する
    lines = []

    return "\n".join(lines)+"\n"

# 3.解答が正しいか判定するコードを書く
def check(test, output):
    """
    test   : generate() で作った入力
    output : SOL が出力した内容

    正しければ
        return True, ""
    間違っていれば
        return False, "間違っている理由"
    """
    test = test.splitlines()
    output = output.splitlines()

    return True, ""

def prepare(filename):
    """
    実行するコマンドを返す。
    Pythonならそのまま。
    C++なら先にコンパイルする。
    """

    if filename.endswith(".py"):
        return [sys.executable, filename]

    if filename.endswith(".cpp"):
        exe = filename[:-4] + ".exe"

        result = subprocess.run(
            [
                "g++",
                filename,
                "-std=c++20",
                "-O2",
                "-o",
                exe,
            ],
            text=True,
            capture_output=True,
        )

        if result.returncode != 0:
            print(f"{filename} のコンパイルに失敗")
            print(result.stderr)
            exit()

        return [exe]

    raise ValueError(f"対応していないファイル形式: {filename}")

def run(command, test):
    try:
        result = subprocess.run(
            command,
            input=test,
            text=True,
            capture_output=True,
            timeout=TIMEOUT_SECOND,
        )
    except subprocess.TimeoutExpired:
        print("TLE!")
        print("command:", command)
        print("===== input =====")
        print(test, end="")
        exit()

    if result.returncode != 0:
        print("RE!")
        print("command:", command)
        print("===== input =====")
        print(test, end="")
        print("===== stderr =====")
        print(result.stderr)
        exit()

    return result.stdout.strip()

sol_command = prepare(SOL)

for t in range(TEST_COUNT):
    test = generate()

    ans = run(sol_command, test)

    try:
        ok, reason = check(test, ans)
    except Exception as e:
        print("Checker Error!")
        print("===== input =====")
        print(test, end="")
        print("===== output =====")
        print(ans)
        print("===== checker error =====")
        print(repr(e))
        break

    if not ok:
        print("WA")
        print("===== input =====")
        print(test, end="")
        print("===== solution =====")
        print(ans)
        print("===== reason =====")
        print(reason)

        with open("failed.txt", "w") as f:
            f.write(test)

        break
else:
    print("All tests passed!")

・ランダムテスト(インタラクティブ)
import subprocess
import sys
import threading
import queue
from random import randrange, shuffle

# 1.ファイル名を書き換える
SOL = ".py"
TEST_COUNT = 100
TIMEOUT_SECOND = 2

# 2.ジャッジが持つ秘密の情報を生成する。
def generate():
    """
    普通のランテスと違って、
    必ずしも文字列を返す必要はない。

    例:
        N = randrange(1, 101)
        X = randrange(1, N+1)
        return N, X
    """

    return None

# 3.インタラクティブジャッジを書く。
def judge(io, case):
    """
    io.send(s)
        解答側に1行送る

    io.recv()
        解答側から1行受け取る

    正解:
        return True, ""

    不正解:
        return False, "理由"
    """

    # ==========================================
    # 例:
    #
    # N, X = case
    #
    # 最初にNを通知
    # io.send(str(N))
    #
    # query_count = 0
    #
    # while True:
    #     line = io.recv()
    #     tokens = line.split()
    #
    #     if len(tokens) == 2 and tokens[0] == "?":
    #         query_count += 1
    #
    #         if query_count > 20:
    #             return False, "質問回数オーバー"
    #
    #         x = int(tokens[1])
    #
    #         if not (1 <= x <= N):
    #             return False, "質問が範囲外"
    #
    #         if X <= x:
    #             io.send("Yes")
    #         else:
    #             io.send("No")
    #
    #     elif len(tokens) == 2 and tokens[0] == "!":
    #         answer = int(tokens[1])
    #
    #         if answer == X:
    #             return True, ""
    #         else:
    #             return False, f"答えが違う: {answer} != {X}"
    #
    #     else:
    #         return False, f"不正な出力: {line}"
    # ==========================================

    return True, ""


def prepare(filename):
    """
    実行するコマンドを返す。
    Pythonならそのまま。
    C++なら先にコンパイルする。
    """

    if filename.endswith(".py"):
        return [sys.executable, filename]

    if filename.endswith(".cpp"):
        exe = filename[:-4] + ".exe"

        result = subprocess.run(
            [
                "g++",
                filename,
                "-std=c++20",
                "-O2",
                "-o",
                exe,
            ],
            text=True,
            capture_output=True,
        )

        if result.returncode != 0:
            print(f"{filename} のコンパイルに失敗")
            print(result.stderr)
            exit()

        return [exe]

    raise ValueError(f"対応していないファイル形式: {filename}")


class InteractiveProcess:
    def __init__(self, command):
        self.proc = subprocess.Popen(
            command,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            bufsize=1,
        )

        self.stdout_queue = queue.Queue()
        self.stderr_lines = []
        self.transcript = []

        self.stdout_thread = threading.Thread(
            target=self._read_stdout,
            daemon=True,
        )
        self.stdout_thread.start()

        self.stderr_thread = threading.Thread(
            target=self._read_stderr,
            daemon=True,
        )
        self.stderr_thread.start()

    def _read_stdout(self):
        for line in self.proc.stdout:
            self.stdout_queue.put(line.rstrip("\r\n"))

        # EOF
        self.stdout_queue.put(None)

    def _read_stderr(self):
        for line in self.proc.stderr:
            self.stderr_lines.append(line)

    def send(self, s):
        """
        ジャッジ → 解答
        """

        if self.proc.poll() is not None:
            raise RuntimeError(
                f"解答プログラムが途中で終了した "
                f"(returncode={self.proc.returncode})"
            )

        s = str(s)

        self.transcript.append(("Judge", s))

        try:
            self.proc.stdin.write(s + "\n")
            self.proc.stdin.flush()
        except BrokenPipeError:
            raise RuntimeError("解答プログラムが入力を受け取る前に終了した")

    def recv(self):
        """
        解答 → ジャッジ
        """

        try:
            line = self.stdout_queue.get(
                timeout=TIMEOUT_SECOND
            )
        except queue.Empty:
            raise TimeoutError(
                f"{TIMEOUT_SECOND} 秒以内に応答がなかった"
            )

        if line is None:
            returncode = self.proc.poll()

            raise RuntimeError(
                f"解答プログラムが途中で終了した "
                f"(returncode={returncode})"
            )

        self.transcript.append(("Solution", line))

        return line

    def finish(self):
        """
        正解判定後、解答プログラムが正常終了するか確認。
        """

        if self.proc.stdin and not self.proc.stdin.closed:
            self.proc.stdin.close()

        try:
            self.proc.wait(timeout=TIMEOUT_SECOND)
        except subprocess.TimeoutExpired:
            raise TimeoutError(
                "正解を通知した後もプログラムが終了しなかった"
            )

        if self.proc.returncode != 0:
            raise RuntimeError(
                f"解答プログラムが異常終了した "
                f"(returncode={self.proc.returncode})"
            )

    def stop(self):
        if self.proc.poll() is None:
            self.proc.kill()
            self.proc.wait()

    def print_transcript(self):
        print("===== transcript =====")

        for side, text in self.transcript:
            print(f"{side:8}: {text}")

    def print_stderr(self):
        if self.stderr_lines:
            print("===== stderr =====")
            print("".join(self.stderr_lines), end="")


sol_command = prepare(SOL)

for t in range(TEST_COUNT):
    case = generate()

    io = InteractiveProcess(sol_command)

    try:
        ok, reason = judge(io, case)

        if not ok:
            print("WA")
            print("===== hidden case =====")
            print(repr(case))
            print("===== reason =====")
            print(reason)

            io.print_transcript()
            io.print_stderr()

            with open("failed.txt", "w") as f:
                f.write(repr(case))

            io.stop()
            break

        io.finish()

    except TimeoutError as e:
        print("TLE!")
        print("===== hidden case =====")
        print(repr(case))
        print("===== reason =====")
        print(e)

        io.print_transcript()
        io.print_stderr()

        with open("failed.txt", "w") as f:
            f.write(repr(case))

        io.stop()
        break

    except RuntimeError as e:
        print("RE / Protocol Error!")
        print("===== hidden case =====")
        print(repr(case))
        print("===== reason =====")
        print(e)

        io.print_transcript()
        io.print_stderr()

        with open("failed.txt", "w") as f:
            f.write(repr(case))

        io.stop()
        break

    except Exception as e:
        print("Judge Error!")
        print("===== hidden case =====")
        print(repr(case))
        print("===== error =====")
        print(repr(e))

        io.print_transcript()
        io.print_stderr()

        io.stop()
        break

    finally:
        io.stop()

else:
    print("All tests passed!")

・等差数列の和
def rangeSUM(l, r, c):
    return (l+r)*c//2

half = pow(2, -1, MOD)
def rangeSUM(l, r, c):
    return (l+r)%MOD*c%MOD*half%MOD

・等差数列MODカウント
def rangeModCount(l, r, c, m, k = 0):
    if l == r:
        return c if l%m == k else 0
    if c == 1: return -1

    if l > r: l, r = r, l
    if (r-l)%(c-1) != 0: return -1

    d = (r-l)//(c-1)

    GCD = gcd(m, d)
    if l%GCD != k%GCD: return 0
    ng = (k-l)//GCD
    mg = m//GCD
    dg = d//GCD
    f = inverse(ng, dg, mg)
    if c <= f:
        return 0
    else:
        return (c-f-1)//mg+1

・重心分解
size = [-1]*N
maxidx = [-1]*N

@bootstrap
def dfs(n, pre):
    history.append(n)
    cnt = 1
    MAX = -(10**18)
    for i, (v, c) in enumerate(G[n]):
        if v != pre and not used[v]:
            c = yield dfs(v, n)
            cnt += c
            if MAX < c:
                MAX = c
                maxidx[n] = i
    size[n] = cnt
    yield size[n]

@bootstrap
def dfs2(n, L):
    if size[G[n][maxidx[n]][0]] > L//2:
        yield (yield dfs2(G[n][maxidx[n]][0], L))
    yield n

parent = [-1]*N
used = [False]*N
que = deque()
que.append((0, -1))
while que:
    n, p = que.popleft()
    history = []
    dfs(n, -1)
    center = dfs2(n, len(history))
    while history:
        h = history.pop()
        size[h] = -1
        maxidx[h] = -1
    used[center] = True
    parent[center] = p
    for v, _ in G[center]:
        if not used[v]:
            que.append((v, center))

・ダブリング
class Doubling:
    def __init__(self, nex, max_k=10**18):
        self.N = len(nex)
        self.LOG = max(1, max_k.bit_length())
        self.dp = [[-1]*self.N for _ in range(self.LOG)]
        self.dp[0] = nex[:]
        for i in range(1, self.LOG):
            for j in range(self.N):
                self.dp[i][j] = self.dp[i-1][self.dp[i-1][j]]

    def jump(self, n, k):
        for i in range(self.LOG):
            if 1<<i & k:
                n = self.dp[i][n]
        return n

・LIS
def LIS_length(A, strict=True):
    dp = []
    bisect = bisect_left if strict else bisect_right

    for a in A:
        idx = bisect(dp, a)
        if idx == len(dp):
            dp.append(a)
        else:
            dp[idx] = a

    return len(dp)

def LIS(A, strict=True):
    N = len(A)
    dp = []
    idx = []
    pre = [-1]*N

    bisect = bisect_left if strict else bisect_right

    for i, a in enumerate(A):
        j = bisect(dp, a)
        if j == len(dp):
            dp.append(a)
            idx.append(i)
        else:
            dp[j] = a
            idx[j] = i
        if j:
            pre[i] = idx[j-1]

    ans = []
    if idx:
        now = idx[-1]
        while now != -1:
            ans.append(now)
            now = pre[now]

    return ans[::-1]

・トポロジカルソート
def TopologicalSort(G):
    N = len(G)
    cnt = [0]*N
    for n in range(N):
        for v in G[n]:
            cnt[v] += 1
    que = deque()
    for n in range(N):
        if cnt[n] == 0:
            que.append(n)
    ans = []
    while que:
        n = que.popleft()
        ans.append(n)
        for v in G[n]:
            cnt[v] -= 1
            if cnt[v] == 0:
                que.append(v)
    return ans if len(ans) == N else None

・トポロジカルソート(辞書順最小)
def TopologicalSortSmall(G):
    N = len(G)
    cnt = [0]*N
    for n in range(N):
        for v in G[n]:
            cnt[v] += 1
    que = []
    for n in range(N):
        if cnt[n] == 0:
            heappush(que, n)
    ans = []
    while que:
        n = heappop(que)
        ans.append(n)
        for v in G[n]:
            cnt[v] -= 1
            if cnt[v] == 0:
                heappush(que, v)
    return ans if len(ans) == N else None

・転倒数(順列)
# Pは0~N-1の順列
def InversionNumber(P):
    N = len(P)
    B = BIT([0]*N)
    ans = 0
    for p in P:
        if p+1 < N:
            ans += B.query(p+1, N)
        B.add(p, 1)
    return ans

・転倒数
def InversionNumber(A):
    D = compress(A)
    L = len(D)
    B = BIT([0]*L)
    ans = 0
    for a in A:
        idx = D[a]
        if idx+1 < L:
            ans += B.query(idx+1, L)
        B.add(idx, 1)
    return ans

・オイラーツアー(部分木)
class EulerTour:
    def __init__(self, G, root=0):
        self.G = G
        self.N = len(self.G)
        self.IN = [-1]*self.N
        self.OUT = [-1]*self.N
        self.REV = [-1]*self.N
        self.dfs(root, -1, 0)

    @bootstrap
    def dfs(self, n, pre, time):
        self.IN[n] = time
        self.REV[time] = n
        for v in self.G[n]:
            if v == pre:
                continue
            time = yield self.dfs(v, n, time+1)
        self.OUT[n] = time
        yield time

    def index(self, n):
        return self.IN[n]

    def interval(self, n):
        return (self.IN[n], self.OUT[n])

    def index_rev(self, n):
        return self.REV[n]

・オイラーツアー(パス(辺))
class EulerTour:
    def __init__(self, G, root=0):
        self.G = G
        self.N = len(self.G)
        self.IN = [-1]*(self.N-1)
        self.OUT = [-1]*(self.N-1)
        self.REV = [-1]*((self.N-1)*2)
        self.dfs(root, -1, 0)

    @bootstrap
    def dfs(self, n, pre, time):
        for v, eidx in self.G[n]:
            if v == pre:
                continue
            self.IN[eidx] = time
            self.REV[time] = eidx
            time += 1
            time = yield self.dfs(v, n, time)
            self.OUT[eidx] = time
            self.REV[time] = eidx
            time += 1
        yield time

    def index_in(self, n):
        return self.IN[n]

    def index_out(self, n):
        return self.OUT[n]

    def interval(self, n):
        return (self.IN[n], self.OUT[n])

    def index_rev(self, n):
        return self.REV[n]

・オイラーツアー(パス(頂点))
class EulerTour:
    def __init__(self, G, root=0):
        self.G = G
        self.N = len(self.G)
        self.IN = [-1]*self.N
        self.OUT = [-1]*self.N
        self.REV = [-1]*(self.N*2)
        self.dfs(root, -1, 0)

    @bootstrap
    def dfs(self, n, pre, time):
        self.IN[n] = time
        self.REV[time] = n
        time += 1
        for v in self.G[n]:
            if v == pre:
                continue
            time = yield self.dfs(v, n, time)
        self.OUT[n] = time
        self.REV[time] = n
        time += 1
        yield time

    def index_in(self, n):
        return self.IN[n]

    def index_out(self, n):
        return self.OUT[n]

    def interval(self, n):
        return (self.IN[n], self.OUT[n])

    def index_rev(self, n):
        return self.REV[n]