import kotlin.math.*
import java.util.*
import java.lang.Integer.min
import java.util.function.Consumer

fun main() {
    println(solve())
}

val solve: () -> Any = solve@{

    val (N,M) = readIntList()
    val dsu = DSU(N)
    repeat(M) {
        readIntList().also {
            dsu.merge(it[0]-1,it[1]-1)
        }
    }
    dsu.groups().size - 1
}
val mod: Int = 1_000_000_007

fun readString() = readLine()!!
fun readStringList() = readLine()!!.split(" ")
fun readInt() = readLine()!!.toInt()
fun readLong() = readLine()!!.toLong()
fun readIntList() = readLine()!!.split(" ").map(String::toInt)
fun readLongList() = readLine()!!.split(" ").map(String::toLong)

fun <T> T.alsoPrintln() = also { println(this) }

fun Boolean.toYesOrNo(yes: String = "Yes", no: String = "No") = if (this) yes else no

fun <E> List<E>.toPair() = this[0] to this[1]

inline fun <reified S, reified T> readPair() =
    readLine()!!.split(" ").let { it[0].stringTo<S>()!! to it[1].stringTo<T>()!! }

inline fun <reified S, reified T, reified U> readTriple() =
    readLine()!!.split(" ").let { Triple(it[0].stringTo<S>()!!, it[1].stringTo<T>()!!, it[2].stringTo<U>()!!) }

inline fun <reified T> String.stringTo(): T? =
    when (T::class) {
        String::class -> this as T
        Int::class -> toInt() as T
        Long::class -> toLong() as T
        else -> null
    }

fun Int.pow(n: Int) = this.toDouble().pow(n).toInt()

fun minAndMax(a: Int, b: Int) = if (a < b) a to b else b to a

fun <T> T.ifOrThis(bool: (T) -> Boolean, trans: (T) -> T) = if (bool(this)) trans(this) else this
fun <T> T.ifOrThis(bool: Boolean, trans: (T) -> T) = if (bool) trans(this) else this

val dir4 = listOf(-1 to 0, 1 to 0, 0 to -1, 0 to 1)

//acl

/**
 * Disjoint set union.
 *
 * convert from [AtCoderLibraryForJava - DSU](https://github.com/NASU41/AtCoderLibraryForJava/blob/24160d880a5fc6d1caf9b95baa875e47fb568ef3/DSU/DSU.java)
 */
class DSU(private val n: Int) {
    private val parentOrSize: IntArray = IntArray(n)

    /**
     * Merge nodes.
     */
    fun merge(a: Int, b: Int): Int {
        if (a !in 0 until n) throw IndexOutOfBoundsException("a=$a")
        if (b !in 0 until n) throw IndexOutOfBoundsException("b=$b")
        var x = leader(a)
        var y = leader(b)
        if (x == y) return x
        if (-parentOrSize[x] < -parentOrSize[y]) {
            val tmp = x
            x = y
            y = tmp
        }
        parentOrSize[x] += parentOrSize[y]
        parentOrSize[y] = x
        return x
    }

    /**
     * True if two nodes are connected.
     */
    fun same(a: Int, b: Int): Boolean {
        if (a !in 0 until n) throw IndexOutOfBoundsException("a=$a")
        if (b !in 0 until n) throw IndexOutOfBoundsException("b=$b")
        return leader(a) == leader(b)
    }

    /**
     * Get its leader node.
     */
    fun leader(a: Int): Int {
        return if (parentOrSize[a] < 0) {
            a
        } else {
            parentOrSize[a] = leader(parentOrSize[a])
            parentOrSize[a]
        }
    }

    /**
     * A group's size.
     */
    fun size(a: Int): Int {
        if (a !in 0 until n) throw IndexOutOfBoundsException("" + a)
        return -parentOrSize[leader(a)]
    }

    /**
     * Group by leader.
     */
    fun groups(): ArrayList<ArrayList<Int>> {
        val leaderBuf = IntArray(n)
        val groupSize = IntArray(n)
        for (i in 0 until n) {
            leaderBuf[i] = leader(i)
            groupSize[leaderBuf[i]]++
        }
        val result = ArrayList<ArrayList<Int>>(n)
        for (i in 0 until n) {
            result.add(ArrayList(groupSize[i]))
        }
        for (i in 0 until n) {
            result[leaderBuf[i]].add(i)
        }
        result.removeIf { obj: ArrayList<Int> -> obj.isEmpty() }
        return result
    }

    init {
        Arrays.fill(parentOrSize, -1)
    }
}

/**
 * Fenwick tree(0-indexed).
 *
 * convert from [AtCoderLibraryForJava - FenwickTree](https://github.com/NASU41/AtCoderLibraryForJava/blob/24160d880a5fc6d1caf9b95baa875e47fb568ef3/FenwickTree/FenwickTree.java)
 */
class FenwickTree(private val n: Int) {
    private val data: LongArray = LongArray(n)

    /**
     * Fenwick tree constructor.
     */
    constructor(data: LongArray) : this(data.size) {
        build(data)
    }

    /**
     * Add value x to p.
     */
    fun add(p: Int, x: Long) {
        var vp = p
        assert(vp in 0 until n)
        vp++
        while (vp <= n) {
            data[vp - 1] += x
            vp += vp and -vp
        }
    }

    /**
     * Calc sum [l, r].
     */
    fun sum(l: Int, r: Int): Long {
        assert(l in 0..r && r <= n)
        return sum(r) - sum(l)
    }

    private fun sum(r: Int): Long {
        var vr = r
        var s: Long = 0
        while (vr > 0) {
            s += data[vr - 1]
            vr -= vr and -vr
        }
        return s
    }

    private fun build(dat: LongArray) {
        System.arraycopy(dat, 0, data, 0, n)
        for (i in 1..n) {
            val p = i + (i and -i)
            if (p <= n) {
                data[p - 1] += data[i - 1]
            }
        }
    }
}

internal object MathLib {
    /**
     * xをmで割った余りを返す.
     */
    fun safeMod(x: Long, m: Long): Long {
        val x = x % m
        return if (x < 0) x + m else x
    }

    fun invGcd(a: Long, b: Long): LongArray {
        var a = a
        a = safeMod(a, b)
        if (a == 0L) return longArrayOf(b, 0)
        var s = b
        var t = a
        var m0: Long = 0
        var m1: Long = 1
        while (t > 0) {
            val u = s / t
            s -= t * u
            m0 -= m1 * u
            var tmp = s
            s = t
            t = tmp
            tmp = m0
            m0 = m1
            m1 = tmp
        }
        if (m0 < 0) m0 += b / s
        return longArrayOf(s, m0)
    }

    /**
     * xのn乗をmで割った余りを返す.
     */
    fun powMod(x: Long, n: Long, m: Long): Long {
        assert(n >= 0 && m >= 1)
        var x = x % m
        var n = n
        var ans = 1L
        while (n > 0) {
            if (n % 2 == 1L) ans = ans * x % m
            x = x * x % m
            n /= 2
        }
        return ans
    }

    fun crt(r: LongArray, m: LongArray): LongArray {
        assert(r.size == m.size)
        val n = r.size
        var r0: Long = 0
        var m0: Long = 1
        for (i in 0 until n) {
            assert(1 <= m[i])
            var r1 = safeMod(r[i], m[i])
            var m1 = m[i]
            if (m0 < m1) {
                var tmp = r0
                r0 = r1
                r1 = tmp
                tmp = m0
                m0 = m1
                m1 = tmp
            }
            if (m0 % m1 == 0L) {
                if (r0 % m1 != r1) return longArrayOf(0, 0)
                continue
            }
            val ig = invGcd(m0, m1)
            val g = ig[0]
            val im = ig[1]
            val u1 = m1 / g
            if ((r1 - r0) % g != 0L) return longArrayOf(0, 0)
            val x = (r1 - r0) / g % u1 * im % u1
            r0 += x * m0
            m0 *= u1
            if (r0 < 0) r0 += m0
            //System.err.printf("%d %d\n", r0, m0);
        }
        return longArrayOf(r0, m0)
    }

    fun floorSum(n: Long, m: Long, a: Long, b: Long): Long {
        var a = a
        var b = b
        var ans: Long = 0
        if (a >= m) {
            ans += (n - 1) * n * (a / m) / 2
            a %= m
        }
        if (b >= m) {
            ans += n * (b / m)
            b %= m
        }
        val yMax = (a * n + b) / m
        val xMax = yMax * m - b
        if (yMax == 0L) return ans
        ans += (n - (xMax + a - 1) / a) * yMax
        ans += floorSum(yMax, a, m, (a - xMax % a) % a)
        return ans
    }
}

/**
 * convert from [AtCoderLibraryForJava - MaxFlow](https://github.com/NASU41/AtCoderLibraryForJava/blob/24160d880a5fc6d1caf9b95baa875e47fb568ef3/MaxFlow/MaxFlow.java)
 */
class MaxFlow(private val n: Int) {
    inner class CapEdge internal constructor(val from: Int, val to: Int, var cap: Long, val rev: Int)

    private var m = 0
    private val edges: ArrayList<CapEdge> = ArrayList()
    private val count: IntArray = IntArray(n)
    private val g: Array<Array<CapEdge?>> = Array(n) { emptyArray<CapEdge?>() }

    fun addEdge(from: Int, to: Int, cap: Long): Int {
        rangeCheck(from, 0, n)
        rangeCheck(to, 0, n)
        nonNegativeCheck(cap, "Capacity")
        val e = CapEdge(from, to, cap, count[to])
        count[from]++
        count[to]++
        edges.add(e)
        return m++
    }

    fun getEdge(i: Int): CapEdge {
        rangeCheck(i, 0, m)
        return edges[i]
    }

    fun changeEdge(i: Int, newCap: Long, newFlow: Long) {
        rangeCheck(i, 0, m)
        nonNegativeCheck(newCap, "Capacity")
        require(newFlow <= newCap) { String.format("Flow %d is greater than capacity %d.", newCap, newFlow) }
        val e = edges[i]
        val er = g[e.to][e.rev]
        e.cap = newCap - newFlow
        er!!.cap = newFlow
    }

    private fun buildGraph() {
        for (i in 0 until n) {
            g[i] = arrayOfNulls(count[i])
        }
        val idx = IntArray(n)
        for (e in edges) {
            g[e.to][idx[e.to]++] = CapEdge(e.to, e.from, 0, idx[e.from])
            g[e.from][idx[e.from]++] = e
        }
    }

    fun maxFlow(s: Int, t: Int): Long {
        return flow(s, t, INF)
    }

    fun flow(s: Int, t: Int, flowLimit: Long): Long {
        rangeCheck(s, 0, n)
        rangeCheck(t, 0, n)
        buildGraph()
        var flow: Long = 0
        val level = IntArray(n)
        val que = IntArray(n)
        val iter = IntArray(n)
        while (true) {
            java.util.Arrays.fill(level, -1)
            dinicBFS(s, t, level, que)
            if (level[t] < 0) return flow
            java.util.Arrays.fill(iter, 0)
            while (true) {
                val d = dinicDFS(t, s, flowLimit - flow, iter, level)
                if (d <= 0) break
                flow += d
            }
        }
    }

    private fun dinicBFS(s: Int, t: Int, level: IntArray, que: IntArray) {
        var hd = 0
        var tl = 0
        que[tl++] = s
        level[s] = 0
        while (tl > hd) {
            val u = que[hd++]
            for (e in g[u]) {
                val v = e!!.to
                if (e.cap <= 0 || level[v] >= 0) continue
                level[v] = level[u] + 1
                if (v == t) return
                que[tl++] = v
            }
        }
    }

    private fun dinicDFS(cur: Int, s: Int, f: Long, iter: IntArray, level: IntArray): Long {
        if (cur == s) return f
        var res: Long = 0
        while (iter[cur] < count[cur]) {
            val er = g[cur][iter[cur]++]
            val u = er!!.to
            val e = g[u][er.rev]
            if (level[u] >= level[cur] || e!!.cap <= 0) continue
            val d = dinicDFS(u, s, Math.min(f - res, e.cap), iter, level)
            if (d <= 0) continue
            e.cap -= d
            er.cap += d
            res += d
            if (res == f) break
        }
        return res
    }

    fun fordFulkersonMaxFlow(s: Int, t: Int): Long {
        return fordFulkersonFlow(s, t, INF)
    }

    fun fordFulkersonFlow(s: Int, t: Int, flowLimit: Long): Long {
        rangeCheck(s, 0, n)
        rangeCheck(t, 0, n)
        buildGraph()
        val used = BooleanArray(n)
        var flow: Long = 0
        while (true) {
            java.util.Arrays.fill(used, false)
            val f = fordFulkersonDFS(s, t, flowLimit - flow, used)
            if (f <= 0) return flow
            flow += f
        }
    }

    private fun fordFulkersonDFS(cur: Int, t: Int, f: Long, used: BooleanArray): Long {
        if (cur == t) return f
        used[cur] = true
        for (e in g[cur]) {
            if (used[e!!.to] || e.cap <= 0) continue
            val d = fordFulkersonDFS(e.to, t, Math.min(f, e.cap), used)
            if (d <= 0) continue
            e.cap -= d
            g[e.to][e.rev]!!.cap += d
            return d
        }
        return 0
    }

    fun minCut(s: Int): BooleanArray {
        rangeCheck(s, 0, n)
        val reachable = BooleanArray(n)
        val stack = IntArray(n)
        var ptr = 0
        stack[ptr++] = s
        reachable[s] = true
        while (ptr > 0) {
            val u = stack[--ptr]
            for (e in g[u]) {
                val v = e!!.to
                if (reachable[v] || e.cap <= 0) continue
                reachable[v] = true
                stack[ptr++] = v
            }
        }
        return reachable
    }

    private fun rangeCheck(i: Int, minInclusive: Int, maxExclusive: Int) {
        if (i < minInclusive || i >= maxExclusive) {
            throw IndexOutOfBoundsException(String.format("Index %d out of bounds for length %d", i, maxExclusive))
        }
    }

    private fun nonNegativeCheck(cap: Long, attribute: String) {
        require(cap >= 0) { String.format("%s %d is negative.", attribute, cap) }
    }

    companion object {
        private const val INF = Long.MAX_VALUE
    }
}

/**
 * convert from [AtCoderLibraryForJava - MinCostFlow](https://github.com/NASU41/AtCoderLibraryForJava/blob/24160d880a5fc6d1caf9b95baa875e47fb568ef3/MinCostFlow/MinCostFlow.java)
 */
class MinCostFlow(private val n: Int) {
    inner class WeightedCapEdge internal constructor(
        val from: Int,
        val to: Int,
        var cap: Long,
        var cost: Long,
        val rev: Int
    )

    private var m = 0
    private val edges: ArrayList<WeightedCapEdge> = ArrayList()
    private val count: IntArray = IntArray(n)
    private val g: Array<Array<WeightedCapEdge?>> = Array(n) { emptyArray<WeightedCapEdge?>() }
    private val potential: LongArray = LongArray(n)
    private val dist: LongArray = LongArray(n)
    private val prev: Array<WeightedCapEdge?> = arrayOfNulls(n)

    fun addEdge(from: Int, to: Int, cap: Long, cost: Long): Int {
        rangeCheck(from, 0, n)
        rangeCheck(to, 0, n)
        nonNegativeCheck(cap, "Capacity")
        nonNegativeCheck(cost, "Cost")
        val e = WeightedCapEdge(from, to, cap, cost, count[to])
        count[from]++
        count[to]++
        edges.add(e)
        return m++
    }

    private fun buildGraph() {
        for (i in 0 until n) {
            g[i] = arrayOfNulls(count[i])
        }
        val idx = IntArray(n)
        for (e in edges) {
            g[e.to][idx[e.to]++] = WeightedCapEdge(e.to, e.from, 0, -e.cost, idx[e.from])
            g[e.from][idx[e.from]++] = e
        }
    }

    private var addFlow: Long = 0
    private var addCost: Long = 0
    fun minCostMaxFlow(s: Int, t: Int): LongArray {
        return minCostFlow(s, t, INF)
    }

    fun minCostFlow(s: Int, t: Int, flowLimit: Long): LongArray {
        rangeCheck(s, 0, n)
        rangeCheck(t, 0, n)
        require(s != t) { String.format("s = t = %d", s) }
        nonNegativeCheck(flowLimit, "Flow")
        buildGraph()
        var flow: Long = 0
        var cost: Long = 0
        while (true) {
            dijkstra(s, t, flowLimit - flow)
            if (addFlow == 0L) break
            flow += addFlow
            cost += addFlow * addCost
        }
        return longArrayOf(flow, cost)
    }

    @JvmOverloads
    fun minCostSlope(s: Int, t: Int, flowLimit: Long = INF): ArrayList<LongArray> {
        rangeCheck(s, 0, n)
        rangeCheck(t, 0, n)
        require(s != t) { String.format("s = t = %d", s) }
        nonNegativeCheck(flowLimit, "Flow")
        buildGraph()
        val slope = ArrayList<LongArray>()
        var prevCost: Long = -1
        var flow: Long = 0
        var cost: Long = 0
        while (true) {
            slope.add(longArrayOf(flow, cost))
            dijkstra(s, t, flowLimit - flow)
            if (addFlow == 0L) return slope
            flow += addFlow
            cost += addFlow * addCost
            if (addCost == prevCost) {
                slope.removeAt(slope.size - 1)
            }
            prevCost = addCost
        }
    }

    private fun dijkstra(s: Int, t: Int, maxFlow: Long) {
        class State(val v: Int, val d: Long) : Comparable<State> {
            override operator fun compareTo(other: State): Int {
                return if (d == other.d) v - other.v else if (d > other.d) 1 else -1
            }
        }
        java.util.Arrays.fill(dist, INF)
        dist[s] = 0
        val pq = java.util.PriorityQueue<State>()
        pq.add(State(s, 0L))
        while (pq.size > 0) {
            val st = pq.poll()
            val u = st.v
            if (st.d != dist[u]) continue
            for (e in g[u]) {
                if (e!!.cap <= 0) continue
                val v = e.to
                val nextCost = dist[u] + e.cost + potential[u] - potential[v]
                if (nextCost < dist[v]) {
                    dist[v] = nextCost
                    prev[v] = e
                    pq.add(State(v, dist[v]))
                }
            }
        }
        if (dist[t] == INF) {
            addFlow = 0
            addCost = INF
            return
        }
        for (i in 0 until n) {
            potential[i] += dist[i]
        }
        addCost = 0
        addFlow = maxFlow
        run {
            var v = t
            while (v != s) {
                val e = prev[v]
                addCost += e!!.cost
                addFlow = Math.min(addFlow, e.cap)
                v = e.from
            }
        }
        var v = t
        while (v != s) {
            val e = prev[v]
            e!!.cap -= addFlow
            g[v][e!!.rev]!!.cap += addFlow
            v = e!!.from
        }
    }

    fun clearFlow() {
        java.util.Arrays.fill(potential, 0)
        for (e in edges) {
            val flow = e.cap
            e.cap += flow
            g[e.to][e.rev]!!.cap -= flow
        }
    }

    fun getEdge(i: Int): WeightedCapEdge {
        rangeCheck(i, 0, m)
        return edges[i]
    }

    private fun rangeCheck(i: Int, minInclusive: Int, maxExclusive: Int) {
        if (i < minInclusive || i >= maxExclusive) {
            throw IndexOutOfBoundsException(String.format("Index %d out of bounds for length %d", i, maxExclusive))
        }
    }

    private fun nonNegativeCheck(cap: Long, attribute: String) {
        require(cap >= 0) { String.format("%s %d is negative.", attribute, cap) }
    }

    companion object {
        private const val INF = Long.MAX_VALUE
    }
}

/** ModInt を生成するためのファクトリ. */
class ModIntFactory(private val mod: Int) {
    private val ma = ModArithmetic.of(mod)

    /**
     * ModInt を生成する.
     * 生成された ModInt は、[value] をファクトリ生成時に指定した mod で割った余りを持つ.
     */
    fun create(value: Long): ModInt {
        val v = (value % mod).let { if (it < 0) it + mod else it }
        return if (ma is ModArithmetic.ModArithmeticMontgomery) {
            ModInt(ma.generate(v))
        } else {
            ModInt(v.toInt())
        }
    }

    inner class ModInt(private var rawValue: Int) {
        val mod = this@ModIntFactory.mod

        val value: Int
            get() = if (ma is ModArithmetic.ModArithmeticMontgomery) {
                ma.reduce(rawValue.toLong())
            } else {
                rawValue
            }

        operator fun plus(mi: ModInt) = ModInt(ma.add(rawValue, mi.rawValue))
        operator fun minus(mi: ModInt) = ModInt(ma.sub(rawValue, mi.rawValue))
        operator fun times(mi: ModInt) = ModInt(ma.mul(rawValue, mi.rawValue))
        operator fun div(mi: ModInt) = ModInt(ma.div(rawValue, mi.rawValue))

        /** (this * inv) % mod = 1 を満たすような inv を ModInt として生成して返す. */
        fun inv() = ModInt(ma.inv(rawValue))

        /** (this ^ [b]) % mod の結果を ModInt として生成して返す. */
        fun pow(b: Long) = ModInt(ma.pow(rawValue, b))

        /** this を this + [mi] に変更する */
        fun addAsg(mi: ModInt): ModInt {
            rawValue = ma.add(rawValue, mi.rawValue)
            return this
        }

        /** this を this - [mi] に変更する */
        fun subAsg(mi: ModInt): ModInt {
            rawValue = ma.sub(rawValue, mi.rawValue)
            return this
        }

        /** this を this * [mi] に変更する */
        fun mulAsg(mi: ModInt): ModInt {
            rawValue = ma.mul(rawValue, mi.rawValue)
            return this
        }

        /** this を this / [mi] に変更する */
        fun divAsg(mi: ModInt): ModInt {
            rawValue = ma.div(rawValue, mi.rawValue)
            return this
        }

        override fun toString(): String {
            return value.toString()
        }

        override fun equals(other: Any?): Boolean {
            if (other is ModInt) {
                return mod == other.mod && value == other.value
            }
            return false
        }

        override fun hashCode(): Int {
            return (1 * 37 + mod) * 37 + value
        }
    }

    internal interface ModArithmetic {
        fun mod(): Int
        fun add(a: Int, b: Int): Int
        fun sub(a: Int, b: Int): Int
        fun mul(a: Int, b: Int): Int
        fun div(a: Int, b: Int): Int {
            return mul(a, inv(b))
        }

        fun inv(a: Int): Int
        fun pow(a: Int, b: Long): Int
        class ModArithmetic1 : ModArithmetic {
            override fun mod(): Int {
                return 1
            }

            override fun add(a: Int, b: Int): Int {
                return 0
            }

            override fun sub(a: Int, b: Int): Int {
                return 0
            }

            override fun mul(a: Int, b: Int): Int {
                return 0
            }

            override fun inv(a: Int): Int {
                throw ArithmeticException("divide by zero")
            }

            override fun pow(a: Int, b: Long): Int {
                return 0
            }
        }

        class ModArithmetic2 : ModArithmetic {
            override fun mod(): Int {
                return 2
            }

            override fun add(a: Int, b: Int): Int {
                return a xor b
            }

            override fun sub(a: Int, b: Int): Int {
                return a xor b
            }

            override fun mul(a: Int, b: Int): Int {
                return a and b
            }

            override fun inv(a: Int): Int {
                if (a == 0) throw ArithmeticException("divide by zero")
                return a
            }

            override fun pow(a: Int, b: Long): Int {
                return if (b == 0L) 1 else a
            }
        }

        class ModArithmetic998244353 : ModArithmetic {
            private val mod = 998244353
            override fun mod(): Int {
                return mod
            }

            override fun add(a: Int, b: Int): Int {
                val res = a + b
                return if (res >= mod) res - mod else res
            }

            override fun sub(a: Int, b: Int): Int {
                val res = a - b
                return if (res < 0) res + mod else res
            }

            override fun mul(a: Int, b: Int): Int {
                return (a.toLong() * b % mod).toInt()
            }

            override fun inv(a: Int): Int {
                var va = a
                var b = mod
                var u: Long = 1
                var v: Long = 0
                while (b >= 1) {
                    val t = (va / b).toLong()
                    va -= (t * b).toInt()
                    val tmp1 = va
                    va = b
                    b = tmp1
                    u -= t * v
                    val tmp2 = u
                    u = v
                    v = tmp2
                }
                u %= mod.toLong()
                if (va != 1) {
                    throw ArithmeticException("divide by zero")
                }
                return (if (u < 0) u + mod else u).toInt()
            }

            override fun pow(a: Int, b: Long): Int {
                var vb = b
                if (vb < 0) throw ArithmeticException("negative power")
                var res: Long = 1
                var pow2 = a.toLong()
                var idx: Long = 1
                while (vb > 0) {
                    val lsb = vb and -vb
                    while (lsb != idx) {
                        pow2 = pow2 * pow2 % mod
                        idx = idx shl 1
                    }
                    res = res * pow2 % mod
                    vb = vb xor lsb
                }
                return res.toInt()
            }
        }

        class ModArithmetic1000000007 : ModArithmetic {
            private val mod = 1000000007
            override fun mod(): Int {
                return mod
            }

            override fun add(a: Int, b: Int): Int {
                val res = a + b
                return if (res >= mod) res - mod else res
            }

            override fun sub(a: Int, b: Int): Int {
                val res = a - b
                return if (res < 0) res + mod else res
            }

            override fun mul(a: Int, b: Int): Int {
                return (a.toLong() * b % mod).toInt()
            }

            override fun div(a: Int, b: Int): Int {
                return mul(a, inv(b))
            }

            override fun inv(a: Int): Int {
                var va = a
                var b = mod
                var u: Long = 1
                var v: Long = 0
                while (b >= 1) {
                    val t = (va / b).toLong()
                    va -= (t * b).toInt()
                    val tmp1 = va
                    va = b
                    b = tmp1
                    u -= t * v
                    val tmp2 = u
                    u = v
                    v = tmp2
                }
                u %= mod.toLong()
                if (va != 1) {
                    throw ArithmeticException("divide by zero")
                }
                return (if (u < 0) u + mod else u).toInt()
            }

            override fun pow(a: Int, b: Long): Int {
                var vb = b
                if (vb < 0) throw ArithmeticException("negative power")
                var res: Long = 1
                var pow2 = a.toLong()
                var idx: Long = 1
                while (vb > 0) {
                    val lsb = vb and -vb
                    while (lsb != idx) {
                        pow2 = pow2 * pow2 % mod
                        idx = idx shl 1
                    }
                    res = res * pow2 % mod
                    vb = vb xor lsb
                }
                return res.toInt()
            }
        }

        class ModArithmeticMontgomery(mod: Int) : ModArithmeticDynamic(mod) {
            private val negInv: Long
            private val r2: Long
            private val r3: Long
            fun generate(x: Long): Int {
                return reduce(x * r2)
            }

            fun reduce(x: Long): Int {
                var vx = x
                vx = vx + (vx * negInv and 0xffffffffL) * mod ushr 32
                return (if (vx < mod) vx else vx - mod).toInt()
            }

            override fun mul(a: Int, b: Int): Int {
                return reduce(a.toLong() * b)
            }

            override fun inv(a: Int): Int {
                var va = a
                va = super.inv(va)
                return reduce(va * r3)
            }

            override fun pow(a: Int, b: Long): Int {
                return generate(super.pow(a, b).toLong())
            }

            init {
                var inv: Long = 0
                var s: Long = 1
                var t: Long = 0
                for (i in 0..31) {
                    if (t and 1 == 0L) {
                        t += mod.toLong()
                        inv += s
                    }
                    t = t shr 1
                    s = s shl 1
                }
                val r = (1L shl 32) % mod
                negInv = inv
                r2 = r * r % mod
                r3 = r2 * r % mod
            }
        }

        class ModArithmeticBarrett(mod: Int) : ModArithmeticDynamic(mod) {
            private val mh: Long
            private val ml: Long
            private fun reduce(x: Long): Int {
                var vx = x
                var z = (vx and mask) * ml
                z = (vx and mask) * mh + (vx ushr 32) * ml + (z ushr 32)
                z = (vx ushr 32) * mh + (z ushr 32)
                vx -= z * mod
                return (if (vx < mod) vx else vx - mod).toInt()
            }

            override fun mul(a: Int, b: Int): Int {
                return reduce(a.toLong() * b)
            }

            companion object {
                private const val mask = 0xffffffffL
            }

            init {
                /**
                 * m = floor(2^64/mod)
                 * 2^64 = p*mod + q, 2^32 = a*mod + b
                 * => (a*mod + b)^2 = p*mod + q
                 * => p = mod*a^2 + 2ab + floor(b^2/mod)
                 */
                val a = (1L shl 32) / mod
                val b = (1L shl 32) % mod
                val m = a * a * mod + 2 * a * b + b * b / mod
                mh = m ushr 32
                ml = m and mask
            }
        }

        open class ModArithmeticDynamic(val mod: Int) : ModArithmetic {
            override fun mod(): Int {
                return mod
            }

            override fun add(a: Int, b: Int): Int {
                val sum = a + b
                return if (sum >= mod) sum - mod else sum
            }

            override fun sub(a: Int, b: Int): Int {
                val sum = a - b
                return if (sum < 0) sum + mod else sum
            }

            override fun mul(a: Int, b: Int): Int {
                return (a.toLong() * b % mod).toInt()
            }

            override fun inv(a: Int): Int {
                var va = a
                var b = mod
                var u: Long = 1
                var v: Long = 0
                while (b >= 1) {
                    val t = (va / b).toLong()
                    va -= (t * b).toInt()
                    val tmp1 = va
                    va = b
                    b = tmp1
                    u -= t * v
                    val tmp2 = u
                    u = v
                    v = tmp2
                }
                u %= mod.toLong()
                if (va != 1) {
                    throw ArithmeticException("divide by zero")
                }
                return (if (u < 0) u + mod else u).toInt()
            }

            override fun pow(a: Int, b: Long): Int {
                var vb = b
                if (vb < 0) throw ArithmeticException("negative power")
                var res = 1
                var pow2 = a
                var idx: Long = 1
                while (vb > 0) {
                    val lsb = vb and -vb
                    while (lsb != idx) {
                        pow2 = mul(pow2, pow2)
                        idx = idx shl 1
                    }
                    res = mul(res, pow2)
                    vb = vb xor lsb
                }
                return res
            }
        }

        companion object {
            fun of(mod: Int): ModArithmetic {
                return when {
                    mod <= 0 -> throw IllegalArgumentException()
                    mod == 1 -> ModArithmetic1()
                    mod == 2 -> ModArithmetic2()
                    mod == 998244353 -> ModArithmetic998244353()
                    mod == 1000000007 -> ModArithmetic1000000007()
                    mod and 1 == 1 -> ModArithmeticMontgomery(mod)
                    else -> ModArithmeticBarrett(mod)
                }
            }
        }
    }
}

/**
 * convert from [AtCoderLibraryForJava - SCC](https://github.com/NASU41/AtCoderLibraryForJava/blob/24160d880a5fc6d1caf9b95baa875e47fb568ef3/SCC/SCC.java)
 */
class SCC(private val n: Int) {
    internal class Edge(var from: Int, var to: Int)

    private var m = 0
    private val unorderedEdges: ArrayList<Edge> = ArrayList()
    private val start: IntArray = IntArray(n + 1)
    private val ids: IntArray = IntArray(n)
    private var hasBuilt = false

    fun addEdge(from: Int, to: Int) {
        rangeCheck(from)
        rangeCheck(to)
        unorderedEdges.add(Edge(from, to))
        start[from + 1]++
        m++
    }

    fun id(i: Int): Int {
        if (!hasBuilt) {
            throw UnsupportedOperationException(
                "Graph hasn't been built."
            )
        }
        rangeCheck(i)
        return ids[i]
    }

    fun build(): Array<IntArray> {
        for (i in 1..n) {
            start[i] += start[i - 1]
        }
        val orderedEdges = arrayOfNulls<Edge>(m)
        val count = IntArray(n + 1)
        System.arraycopy(start, 0, count, 0, n + 1)
        for (e in unorderedEdges) {
            orderedEdges[count[e.from]++] = e
        }
        var nowOrd = 0
        var groupNum = 0
        var k = 0
        // parent
        val par = IntArray(n)
        val vis = IntArray(n)
        val low = IntArray(n)
        val ord = IntArray(n)
        java.util.Arrays.fill(ord, -1)
        // u = lower32(stack[i]) : visiting vertex
        // j = upper32(stack[i]) : jth child
        val stack = LongArray(n)
        // size of stack
        var ptr = 0
        // non-recursional DFS
        for (i in 0 until n) {
            if (ord[i] >= 0) continue
            par[i] = -1
            // vertex i, 0th child.
            stack[ptr++] = 0L shl 32 or i.toLong()
            // stack is not empty
            while (ptr > 0) {
                // last element
                val p = stack[--ptr]
                // vertex
                val u = (p and 0xffffffffL).toInt()
                // jth child
                var j = (p ushr 32).toInt()
                if (j == 0) { // first visit
                    ord[u] = nowOrd++
                    low[u] = ord[u]
                    vis[k++] = u
                }
                if (start[u] + j < count[u]) { // there are more children
                    // jth child
                    val to = orderedEdges[start[u] + j]!!.to
                    // incr children counter
                    stack[ptr++] += 1L shl 32
                    if (ord[to] == -1) { // new vertex
                        stack[ptr++] = 0L shl 32 or to.toLong()
                        par[to] = u
                    } else { // backward edge
                        low[u] = Math.min(low[u], ord[to])
                    }
                } else { // no more children (leaving)
                    while (j-- > 0) {
                        val to = orderedEdges[start[u] + j]!!.to
                        // update lowlink
                        if (par[to] == u) low[u] = Math.min(low[u], low[to])
                    }
                    if (low[u] == ord[u]) { // root of a component
                        while (true) { // gathering verticies
                            val v = vis[--k]
                            ord[v] = n
                            ids[v] = groupNum
                            if (v == u) break
                        }
                        groupNum++ // incr the number of components
                    }
                }
            }
        }
        for (i in 0 until n) {
            ids[i] = groupNum - 1 - ids[i]
        }
        val counts = IntArray(groupNum)
        for (x in ids) counts[x]++
        val groups = Array(groupNum) { intArrayOf() }
        for (i in 0 until groupNum) {
            groups[i] = IntArray(counts[i])
        }
        for (i in 0 until n) {
            val cmp = ids[i]
            groups[cmp][--counts[cmp]] = i
        }
        hasBuilt = true
        return groups
    }

    private fun rangeCheck(i: Int) {
        if (i < 0 || i >= n) {
            throw IndexOutOfBoundsException(String.format("Index %d out of bounds for length %d", i, n))
        }
    }

}

/**
 * Segment tree(0-indexed)
 *
 * convert from [AtCoderLibraryForJava - SegTree](https://github.com/NASU41/AtCoderLibraryForJava/blob/24160d880a5fc6d1caf9b95baa875e47fb568ef3/SegTree/SegTree.java)
 */
class SegTree<S>(n: Int, op: java.util.function.BinaryOperator<S>, e: S) {
    private val max: Int = n
    private val n: Int
    private val op: java.util.function.BinaryOperator<S>
    private val e: S
    private val data: Array<S>

    init {
        var k = 1
        while (k < n) k = k shl 1
        this.n = k
        this.e = e
        this.op = op
        @Suppress("UNCHECKED_CAST")
        data = Array(this.n shl 1) { e as Any } as Array<S>
        java.util.Arrays.fill(data, this.e)
    }

    constructor(dat: Array<S>, op: java.util.function.BinaryOperator<S>, e: S) : this(dat.size, op, e) {
        build(dat)
    }

    private fun build(dat: Array<S>) {
        val l = dat.size
        System.arraycopy(dat, 0, data, n, l)
        for (i in n - 1 downTo 1) {
            data[i] = op.apply(data[i shl 1 or 0], data[i shl 1 or 1])
        }
    }

    operator fun set(p: Int, x: S) {
        var vp = p
        exclusiveRangeCheck(vp)
        data[n.let { vp += it; vp }] = x
        vp = vp shr 1
        while (vp > 0) {
            data[vp] = op.apply(data[vp shl 1 or 0], data[vp shl 1 or 1])
            vp = vp shr 1
        }
    }

    operator fun get(p: Int): S {
        exclusiveRangeCheck(p)
        return data[p + n]
    }

    fun prod(l: Int, r: Int): S {
        var vl = l
        var vr = r
        require(vl <= vr) { String.format("Invalid range: [%d, %d)", vl, vr) }
        inclusiveRangeCheck(vl)
        inclusiveRangeCheck(vr)
        var sumLeft = e
        var sumRight = e
        vl += n
        vr += n
        while (vl < vr) {
            if (vl and 1 == 1) sumLeft = op.apply(sumLeft, data[vl++])
            if (vr and 1 == 1) sumRight = op.apply(data[--vr], sumRight)
            vl = vl shr 1
            vr = vr shr 1
        }
        return op.apply(sumLeft, sumRight)
    }

    fun allProd(): S {
        return data[1]
    }

    fun maxRight(l: Int, f: java.util.function.Predicate<S>): Int {
        var vl = l
        inclusiveRangeCheck(vl)
        require(f.test(e)) { "Identity element must satisfy the condition." }
        if (vl == max) return max
        vl += n
        var sum = e
        do {
            vl = vl shr Integer.numberOfTrailingZeros(vl)
            if (!f.test(op.apply(sum, data[vl]))) {
                while (vl < n) {
                    vl = vl shl 1
                    if (f.test(op.apply(sum, data[vl]))) {
                        sum = op.apply(sum, data[vl])
                        vl++
                    }
                }
                return vl - n
            }
            sum = op.apply(sum, data[vl])
            vl++
        } while (vl and -vl != vl)
        return max
    }

    fun minLeft(r: Int, f: java.util.function.Predicate<S>): Int {
        var vr = r
        inclusiveRangeCheck(vr)
        require(f.test(e)) { "Identity element must satisfy the condition." }
        if (vr == 0) return 0
        vr += n
        var sum = e
        do {
            vr--
            while (vr > 1 && vr and 1 == 1) vr = vr shr 1
            if (!f.test(op.apply(data[vr], sum))) {
                while (vr < n) {
                    vr = vr shl 1 or 1
                    if (f.test(op.apply(data[vr], sum))) {
                        sum = op.apply(data[vr], sum)
                        vr--
                    }
                }
                return vr + 1 - n
            }
            sum = op.apply(data[vr], sum)
        } while (vr and -vr != vr)
        return 0
    }

    private fun exclusiveRangeCheck(p: Int) {
        if (p < 0 || p >= max) {
            throw IndexOutOfBoundsException(String.format("Index %d out of bounds for the range [%d, %d).", p, 0, max))
        }
    }

    private fun inclusiveRangeCheck(p: Int) {
        if (p < 0 || p > max) {
            throw IndexOutOfBoundsException(String.format("Index %d out of bounds for the range [%d, %d].", p, 0, max))
        }
    }
}


object StringAlgorithm {
    private fun saNaive(s: IntArray): IntArray {
        val n = s.size
        val sb = arrayOfNulls<Int>(n)
        for (i in 0 until n) {
            sb[i] = i
        }
        Arrays.sort(sb) { l: Int?, r: Int? ->
            var vl = l
            var vr = r
            while (vl!! < n && vr!! < n) {
                if (s[vl] != s[vr]) return@sort s[vl] - s[vr]
                vl++
                vr++
            }
            -(vl - vr!!)
        }
        val sa = IntArray(n)
        for (i in 0 until n) {
            sa[i] = sb[i]!!
        }
        return sa
    }

    private fun saDoubling(s: IntArray): IntArray {
        val n = s.size
        val sb = arrayOfNulls<Int>(n)
        for (i in 0 until n) {
            sb[i] = i
        }
        var rnk = s
        var tmp = IntArray(n)
        var k = 1
        while (k < n) {
            val vk = k
            val vrnk = rnk
            val cmp = Comparator { x: Int?, y: Int? ->
                if (vrnk[x!!] != vrnk[y!!]) {
                    vrnk[x] - vrnk[y]
                } else {
                    val rx = if (x + vk < n) vrnk[x + vk] else -1
                    val ry = if (y + vk < n) vrnk[y + vk] else -1
                    rx - ry
                }
            }
            Arrays.sort(sb, cmp)
            tmp[sb[0]!!] = 0
            for (i in 1 until n) {
                tmp[sb[i]!!] = tmp[sb[i - 1]!!] + if (cmp.compare(sb[i - 1], sb[i]) < 0) 1 else 0
            }
            val buf = tmp
            tmp = rnk
            rnk = buf
            k *= 2
        }
        val sa = IntArray(n)
        for (i in 0 until n) {
            sa[i] = sb[i]!!
        }
        return sa
    }

    private const val THRESHOLD_NAIVE = 10
    private const val THRESHOLD_DOUBLING = 40
    private fun sais(s: IntArray, upper: Int): IntArray {
        val n = s.size
        if (n == 0) return IntArray(0)
        if (n == 1) return intArrayOf(0)
        if (n == 2) {
            return if (s[0] < s[1]) {
                intArrayOf(0, 1)
            } else {
                intArrayOf(1, 0)
            }
        }
        if (n < THRESHOLD_NAIVE) {
            return saNaive(s)
        }
        if (n < THRESHOLD_DOUBLING) {
            return saDoubling(s)
        }
        val sa = IntArray(n)
        val ls = BooleanArray(n)
        for (i in n - 2 downTo 0) {
            ls[i] = if (s[i] == s[i + 1]) ls[i + 1] else s[i] < s[i + 1]
        }
        val sumL = IntArray(upper + 1)
        val sumS = IntArray(upper + 1)
        for (i in 0 until n) {
            if (ls[i]) {
                sumL[s[i] + 1]++
            } else {
                sumS[s[i]]++
            }
        }
        for (i in 0..upper) {
            sumS[i] += sumL[i]
            if (i < upper) sumL[i + 1] += sumS[i]
        }
        val induce = Consumer { lms: IntArray ->
            Arrays.fill(sa, -1)
            val buf = IntArray(upper + 1)
            System.arraycopy(sumS, 0, buf, 0, upper + 1)
            for (d in lms) {
                if (d == n) continue
                sa[buf[s[d]]++] = d
            }
            System.arraycopy(sumL, 0, buf, 0, upper + 1)
            sa[buf[s[n - 1]]++] = n - 1
            for (i in 0 until n) {
                val v = sa[i]
                if (v >= 1 && !ls[v - 1]) {
                    sa[buf[s[v - 1]]++] = v - 1
                }
            }
            System.arraycopy(sumL, 0, buf, 0, upper + 1)
            for (i in n - 1 downTo 0) {
                val v = sa[i]
                if (v >= 1 && ls[v - 1]) {
                    sa[--buf[s[v - 1] + 1]] = v - 1
                }
            }
        }
        val lmsMap = IntArray(n + 1)
        Arrays.fill(lmsMap, -1)
        var m = 0
        for (i in 1 until n) {
            if (!ls[i - 1] && ls[i]) {
                lmsMap[i] = m++
            }
        }
        val lms = IntArray(m)
        run {
            var p = 0
            for (i in 1 until n) {
                if (!ls[i - 1] && ls[i]) {
                    lms[p++] = i
                }
            }
        }
        induce.accept(lms)
        if (m > 0) {
            val sortedLms = IntArray(m)
            run {
                var p = 0
                for (v in sa) {
                    if (lmsMap[v] != -1) {
                        sortedLms[p++] = v
                    }
                }
            }
            val recS = IntArray(m)
            var recUpper = 0
            recS[lmsMap[sortedLms[0]]] = 0
            for (i in 1 until m) {
                var l = sortedLms[i - 1]
                var r = sortedLms[i]
                val endL = if (lmsMap[l] + 1 < m) lms[lmsMap[l] + 1] else n
                val endR = if (lmsMap[r] + 1 < m) lms[lmsMap[r] + 1] else n
                var same = true
                if (endL - l != endR - r) {
                    same = false
                } else {
                    while (l < endL && s[l] == s[r]) {
                        l++
                        r++
                    }
                    if (l == n || s[l] != s[r]) same = false
                }
                if (!same) {
                    recUpper++
                }
                recS[lmsMap[sortedLms[i]]] = recUpper
            }
            val recSA = sais(recS, recUpper)
            for (i in 0 until m) {
                sortedLms[i] = lms[recSA[i]]
            }
            induce.accept(sortedLms)
        }
        return sa
    }

    fun suffixArray(s: IntArray, upper: Int): IntArray {
        assert(0 <= upper)
        for (d in s) {
            assert(d in 0..upper)
        }
        return sais(s, upper)
    }

    fun suffixArray(s: IntArray): IntArray {
        val n = s.size
        val idx = arrayOfNulls<Int>(n)
        for (i in 0 until n) {
            idx[i] = i
        }
        Arrays.sort(idx) { l: Int?, r: Int? -> s[l!!] - s[r!!] }
        val s2 = IntArray(n)
        var now = 0
        for (i in 0 until n) {
            if (i > 0 && s[idx[i - 1]!!] != s[idx[i]!!]) {
                now++
            }
            s2[idx[i]!!] = now
        }
        return sais(s2, now)
    }

    fun suffixArray(s: CharArray): IntArray {
        val n = s.size
        val s2 = IntArray(n)
        for (i in 0 until n) {
            s2[i] = s[i].toInt()
        }
        return sais(s2, 255)
    }

    fun suffixArray(s: String): IntArray {
        return suffixArray(s.toCharArray())
    }

    fun lcpArray(s: IntArray, sa: IntArray): IntArray {
        val n = s.size
        assert(n >= 1)
        val rnk = IntArray(n)
        for (i in 0 until n) {
            rnk[sa[i]] = i
        }
        val lcp = IntArray(n - 1)
        var h = 0
        for (i in 0 until n) {
            if (h > 0) h--
            if (rnk[i] == 0) {
                continue
            }
            val j = sa[rnk[i] - 1]
            while (j + h < n && i + h < n) {
                if (s[j + h] != s[i + h]) break
                h++
            }
            lcp[rnk[i] - 1] = h
        }
        return lcp
    }

    fun lcpArray(s: CharArray, sa: IntArray): IntArray {
        val n = s.size
        val s2 = IntArray(n)
        for (i in 0 until n) {
            s2[i] = s[i].toInt()
        }
        return lcpArray(s2, sa)
    }

    fun lcpArray(s: String, sa: IntArray): IntArray {
        return lcpArray(s.toCharArray(), sa)
    }

    fun zAlgorithm(s: IntArray): IntArray {
        val n = s.size
        if (n == 0) return IntArray(0)
        val z = IntArray(n)
        var i = 1
        var j = 0
        while (i < n) {
            var k = if (j + z[j] <= i) 0 else min(j + z[j] - i, z[i - j])
            while (i + k < n && s[k] == s[i + k]) k++
            z[i] = k
            if (j + z[j] < i + z[i]) j = i
            i++
        }
        z[0] = n
        return z
    }

    fun zAlgorithm(s: CharArray): IntArray {
        val n = s.size
        if (n == 0) return IntArray(0)
        val z = IntArray(n)
        var i = 1
        var j = 0
        while (i < n) {
            var k = if (j + z[j] <= i) 0 else min(j + z[j] - i, z[i - j])
            while (i + k < n && s[k] == s[i + k]) k++
            z[i] = k
            if (j + z[j] < i + z[i]) j = i
            i++
        }
        z[0] = n
        return z
    }

    fun zAlgorithm(s: String): IntArray {
        return zAlgorithm(s.toCharArray())
    }
}

/**
 * convert from [AtCoderLibraryForJava - TwoSAT](https://github.com/NASU41/AtCoderLibraryForJava/blob/24160d880a5fc6d1caf9b95baa875e47fb568ef3/2SAT/TwoSAT.java)
 */
class TwoSAT(private val n: Int) {
    private val scc: InternalSCC = InternalSCC(2 * n)
    private val answer: BooleanArray = BooleanArray(n)
    private var hasCalledSatisfiable = false
    private var existsAnswer = false

    fun addClause(x: Int, f: Boolean, y: Int, g: Boolean) {
        rangeCheck(x)
        rangeCheck(y)
        scc.addEdge(x shl 1 or if (f) 0 else 1, y shl 1 or if (g) 1 else 0)
        scc.addEdge(y shl 1 or if (g) 0 else 1, x shl 1 or if (f) 1 else 0)
    }

    fun addImplication(x: Int, f: Boolean, y: Int, g: Boolean) {
        addClause(x, !f, y, g)
    }

    fun addNand(x: Int, f: Boolean, y: Int, g: Boolean) {
        addClause(x, !f, y, !g)
    }

    fun satisfiable(): Boolean {
        hasCalledSatisfiable = true
        val ids = scc.ids()
        for (i in 0 until n) {
            if (ids[i shl 1 or 0] == ids[i shl 1 or 1]) return false.also { existsAnswer = it }
            answer[i] = ids[i shl 1 or 0] < ids[i shl 1 or 1]
        }
        return true.also { existsAnswer = it }
    }

    fun answer(): BooleanArray? {
        if (!hasCalledSatisfiable) {
            throw UnsupportedOperationException(
                "Call TwoSAT#satisfiable at least once before TwoSAT#answer."
            )
        }
        return if (existsAnswer) answer else null
    }

    private fun rangeCheck(x: Int) {
        if (0 < x || x >= n) {
            throw IndexOutOfBoundsException(String.format("Index %d out of bounds for length %d", x, n))
        }
    }

    private class EdgeList(cap: Int) {
        var a: LongArray
        var ptr = 0
        fun add(upper: Int, lower: Int) {
            if (ptr == a.size) grow()
            a[ptr++] = upper.toLong() shl 32 or lower.toLong()
        }

        fun grow() {
            val b = LongArray(a.size shl 1)
            System.arraycopy(a, 0, b, 0, a.size)
            a = b
        }

        init {
            a = LongArray(cap)
        }
    }

    private class InternalSCC(val n: Int) {
        var m = 0
        val unorderedEdges: EdgeList = EdgeList(n)
        val start: IntArray = IntArray(n + 1)
        fun addEdge(from: Int, to: Int) {
            unorderedEdges.add(from, to)
            start[from + 1]++
            m++
        }

        fun ids(): IntArray {
            for (i in 1..n) {
                start[i] += start[i - 1]
            }
            val orderedEdges = IntArray(m)
            val count = IntArray(n + 1)
            System.arraycopy(start, 0, count, 0, n + 1)
            for (i in 0 until m) {
                val e = unorderedEdges.a[i]
                orderedEdges[count[(e ushr 32).toInt()]++] = (e and mask).toInt()
            }
            var nowOrd = 0
            var groupNum = 0
            var k = 0
            val par = IntArray(n)
            val vis = IntArray(n)
            val low = IntArray(n)
            val ord = IntArray(n)
            java.util.Arrays.fill(ord, -1)
            val ids = IntArray(n)
            val stack = LongArray(n)
            var ptr = 0
            for (i in 0 until n) {
                if (ord[i] >= 0) continue
                par[i] = -1
                stack[ptr++] = i.toLong()
                while (ptr > 0) {
                    val p = stack[--ptr]
                    val u = (p and mask).toInt()
                    var j = (p ushr 32).toInt()
                    if (j == 0) {
                        ord[u] = nowOrd++
                        low[u] = ord[u]
                        vis[k++] = u
                    }
                    if (start[u] + j < count[u]) {
                        val to = orderedEdges[start[u] + j]
                        stack[ptr++] += 1L shl 32
                        if (ord[to] == -1) {
                            stack[ptr++] = to.toLong()
                            par[to] = u
                        } else {
                            low[u] = kotlin.math.min(low[u], ord[to])
                        }
                    } else {
                        while (j-- > 0) {
                            val to = orderedEdges[start[u] + j]
                            if (par[to] == u) low[u] = kotlin.math.min(low[u], low[to])
                        }
                        if (low[u] == ord[u]) {
                            while (true) {
                                val v = vis[--k]
                                ord[v] = n
                                ids[v] = groupNum
                                if (v == u) break
                            }
                            groupNum++
                        }
                    }
                }
            }
            for (i in 0 until n) {
                ids[i] = groupNum - 1 - ids[i]
            }
            return ids
        }

        companion object {
            const val mask = 0xffffffffL
        }

    }
}


Measured memory_bytes: 63844