結果
問題 | No.1054 Union add query |
ユーザー | yakamoto |
提出日時 | 2020-05-15 22:17:17 |
言語 | Kotlin (1.9.23) |
結果 |
AC
|
実行時間 | 1,620 ms / 2,000 ms |
コード長 | 5,976 bytes |
コンパイル時間 | 16,956 ms |
コンパイル使用メモリ | 470,756 KB |
実行使用メモリ | 183,376 KB |
最終ジャッジ日時 | 2024-09-19 11:00:01 |
合計ジャッジ時間 | 29,520 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge4 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 273 ms
54,452 KB |
testcase_01 | AC | 278 ms
54,584 KB |
testcase_02 | AC | 268 ms
54,448 KB |
testcase_03 | AC | 1,337 ms
126,512 KB |
testcase_04 | AC | 1,620 ms
182,452 KB |
testcase_05 | AC | 1,330 ms
118,524 KB |
testcase_06 | AC | 1,239 ms
137,484 KB |
testcase_07 | AC | 1,207 ms
141,876 KB |
testcase_08 | AC | 1,203 ms
137,180 KB |
testcase_09 | AC | 1,506 ms
183,376 KB |
testcase_10 | AC | 1,036 ms
181,364 KB |
ソースコード
import java.io.BufferedReader import java.io.InputStream import java.io.InputStreamReader import java.util.* import kotlin.math.abs import kotlin.math.max import kotlin.math.min val MOD = 1_000_000_007L /** * @param n 個数 最大値じゃないぞ。 * iの範囲は[0, n - 1] * * AがIntやLongのときは埋め込んでしまおう * type A = Int */ class RangeUpdateTree(n: Int, private val zero: Int, private val f: (Int, Int) -> Int) { private val N = if (Integer.highestOneBit(n) == n) n else Integer.highestOneBit(n) shl 1 private val dat = IntArray(2 * N){zero} /** * [l, r) */ fun add(l: Int, r: Int, a: Int) { var left = l + N var right = r - 1 + N while(left <= right) { if ((left and 1) == 1) dat[left] = f(dat[left], a) if ((right and 1) == 0) dat[right] = f(dat[right], a) left = (left + 1) shr 1 // 右の子供なら右の親に移動 right = (right - 1) shr 1 // 左の子供なら左の親に移動 } } fun query(i: Int): Int { var ix = N + i var res: Int = zero while(ix >= 1) { res = f(res, dat[ix]) ix = ix shr 1 } return res } } class UnionFind0(n: Int) { private val par = IntArray(n){it} val rank = Array(n){ val a = mutableListOf<Int>() a += it a } private val visits = IntArray(n) // 訪れた場所をfind毎に用意するのがもったいないのでつかいまわす fun find(x: Int): Int { var ptr = 0 var i = x while(par[i] != i) { visits[ptr++] = i i = par[i] } repeat(ptr){ par[visits[it]] = i } return i } private fun merge(node: Int, rt: Int): Int { par[node] = rt rank[rt].addAll(rank[node]) rank[node].clear() return rt } fun unite(x: Int, y: Int): Int { val x1 = find(x) val y1 = find(y) return if (x1 == y1) x1 else { if (rank[x1].size < rank[y1].size) merge(x1, y1) else merge(y1, x1) } } } data class Seg(var l: Int, var r: Int) class UnionFind1(n: Int, P: IntArray) { private val par = IntArray(n){it} val rank = IntArray(n){1} // 集合の要素数 val seg = Array(n){Seg(P[it], P[it] + 1)} private val visits = IntArray(n) // 訪れた場所をfind毎に用意するのがもったいないのでつかいまわす fun find(x: Int): Int { var ptr = 0 var i = x while(par[i] != i) { visits[ptr++] = i i = par[i] } repeat(ptr){ par[visits[it]] = i } return i } private fun merge(node: Int, rt: Int): Int { par[node] = rt rank[rt] += rank[node] seg[rt].l = min(seg[rt].l, seg[node].l) seg[rt].r = max(seg[rt].r, seg[node].r) return rt } fun unite(x: Int, y: Int): Int { val x1 = find(x) val y1 = find(y) return if (x1 == y1) x1 else { if (rank[x1] < rank[y1]) merge(x1, y1) else merge(y1, x1) } } /** * xを解決する必要がないときは直にrankをみる */ fun cntNodes(x: Int): Int = rank[find(x)] } data class Query(val t: Int, val a: Int, val b: Int) class Solver(stream: InputStream, private val out: java.io.PrintWriter) { fun solve() { val N = ni() val M = ni() val uf0 = UnionFind0(N) val Q = Array(M) {Query(ni(), ni(), ni())} for (q in Q) { if (q.t == 1) { uf0.unite(q.a - 1, q.b - 1) } } val P = mutableListOf<Int>() for (i in 0 until N) { if (uf0.find(i) == i) { for (j in uf0.rank[i]) P += j } } debug{ P.joinToString(" ") } val revP = IntArray(N) for (i in 0 until N) { revP[P[i]] = i } val t = RangeUpdateTree(N, 0, Int::plus) val uf = UnionFind1(N, revP) for (q in Q) { if (q.t == 1) { uf.unite(q.a - 1, q.b - 1) } else if (q.t == 2) { val seg = uf.seg[uf.find(q.a - 1)] t.add(seg.l, seg.r, q.b) } else { out.println(t.query(revP[q.a - 1])) } } } private val isDebug = try { // なんか本番でエラーでる System.getenv("MY_DEBUG") != null } catch (t: Throwable) { false } private var tokenizer: StringTokenizer? = null private val reader = BufferedReader(InputStreamReader(stream), 32768) private fun next(): String { while (tokenizer == null || !tokenizer!!.hasMoreTokens()) { tokenizer = StringTokenizer(reader.readLine()) } return tokenizer!!.nextToken() } private fun ni() = next().toInt() private fun nl() = next().toLong() private fun ns() = next() private fun na(n: Int, offset: Int = 0): IntArray { return map(n) { ni() + offset } } private fun nal(n: Int, offset: Int = 0): LongArray { val res = LongArray(n) for (i in 0 until n) { res[i] = nl() + offset } return res } private fun na2(n: Int, offset: Int = 0): Array<IntArray> { val a = Array(2){IntArray(n)} for (i in 0 until n) { for (e in a) { e[i] = ni() + offset } } return a } private inline fun map(n: Int, f: (Int) -> Int): IntArray { val res = IntArray(n) for (i in 0 until n) { res[i] = f(i) } return res } private inline fun debug(msg: () -> String) { if (isDebug) System.err.println(msg()) } private fun debug(a: LongArray) { debug { a.joinToString(" ") } } private fun debug(a: IntArray) { debug { a.joinToString(" ") } } private fun debug(a: BooleanArray) { debug { a.map { if (it) 1 else 0 }.joinToString("") } } private fun debugDim(A: Array<IntArray>) { if (isDebug) { for (a in A) { debug(a) } } } /** * 勝手にimport消されるのを防ぎたい */ private fun hoge() { min(1, 2) max(1, 2) abs(-10) } } fun main() { val out = java.io.PrintWriter(System.out) Solver(System.`in`, out).solve() out.flush() }