Решение
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import kotlin.math.min
import kotlin.math.max
// Узел сегментного дерева: хранит значение (prod) и индекс (для разрешения равенств – выбираем меньший индекс)
data class Node(val prod: Long, val idx: Int)
fun main(args: Array<String>) {
val reader = BufferedReader(InputStreamReader(System.`in`))
val writer = BufferedWriter(OutputStreamWriter(System.out))
// Считываем n, m, q
val firstLine = reader.readLine().split(" ")
val n = firstLine[0].toInt()
val m = firstLine[1].toInt()
val q = firstLine[2].toInt()
// Для каждого датацентра (индексы 0..n-1)
// R – число перезапусков (начальное 0)
// A – число рабочих серверов (начальное m)
val R = IntArray(n) { 0 }
val A = IntArray(n) { m }
// prod[i] = R[i]*A[i], изначально 0
val prod = LongArray(n) { 0L }
// version[i]: начнем с 1; при RESET будем увеличивать
val version = IntArray(n) { 1 }
// Для каждого датацентра создадим массив для серверов (размер m)
// Каждый элемент – int, обозначающий версию, в которой сервер был отключён; изначально 0 (не соответствует текущей version)
val disabled = Array(n) { IntArray(m) { 0 } }
// Теперь реализуем итератив сегментное дерево для точечных обновлений.
// Найдем минимальную степень двойки >= n.
var size = 1
while (size < n) size *= 2
// Для max-дерева: identity – Node(-1, n) (поскольку все prod>=0)
val INF = 1_000_000_000_000_000_000L // большого значения не понадобится; для min используем, например, 1e15+1
// Для min-дерева: identity – Node(1e15, n) (продукты не превысят примерно 1e11)
val identityMax = Node(-1L, n)
val identityMin = Node(1_000_000_000_000_000L, n)
val segMax = Array(2 * size) { identityMax }
val segMin = Array(2 * size) { identityMin }
// Инициализируем листья по данным prod; изначально все 0
for (i in 0 until n) {
segMax[size + i] = Node(prod[i], i)
segMin[size + i] = Node(prod[i], i)
}
for (i in n until size) {
segMax[size + i] = identityMax
segMin[size + i] = identityMin
}
// Функции слияния для max и min:
fun mergeMax(a: Node, b: Node): Node {
return when {
a.prod > b.prod -> a
a.prod < b.prod -> b
else -> if (a.idx < b.idx) a else b
}
}
fun mergeMin(a: Node, b: Node): Node {
return when {
a.prod < b.prod -> a
a.prod > b.prod -> b
else -> if (a.idx < b.idx) a else b
}
}
// Построим дерево.
for (i in size - 1 downTo 1) {
segMax[i] = mergeMax(segMax[2 * i], segMax[2 * i + 1])
segMin[i] = mergeMin(segMin[2 * i], segMin[2 * i + 1])
}
// Функция обновления для датацентра index (0-indexed) с новым значением prod.
fun update(index: Int, value: Long) {
var pos = index + size
segMax[pos] = Node(value, index)
segMin[pos] = Node(value, index)
pos /= 2
while (pos >= 1) {
segMax[pos] = mergeMax(segMax[2 * pos], segMax[2 * pos + 1])
segMin[pos] = mergeMin(segMin[2 * pos], segMin[2 * pos + 1])
pos /= 2
}
}
// Процесс обработки q событий
for (qq in 0 until q) {
val parts = reader.readLine().split(" ")
when (parts[0]) {
"RESET" -> {
// RESET i
val iDC = parts[1].toInt() - 1
R[iDC]++ // увеличиваем число перезапусков
version[iDC]++ // увеличиваем версию
A[iDC] = m // восстанавливаем число рабочих серверов
prod[iDC] = R[iDC].toLong() * A[iDC].toLong()
update(iDC, prod[iDC])
}
"DISABLE" -> {
// DISABLE i j
val iDC = parts[1].toInt() - 1
val jServer = parts[2].toInt() - 1
// Если сервер уже отключён (в текущей версии) – ничего не делаем.
if (disabled[iDC][jServer] != version[iDC]) {
disabled[iDC][jServer] = version[iDC] // помечаем его как отключённый в текущей версии
if (A[iDC] > 0) {
A[iDC]--
prod[iDC] = R[iDC].toLong() * A[iDC].toLong()
update(iDC, prod[iDC])
}
}
}
"GETMAX" -> {
// Выводим (1-indexированный) номер датацентра с наибольшим prod
writer.write("${segMax[1].idx + 1}")
writer.newLine()
}
"GETMIN" -> {
// Выводим (1-indexированный) номер датацентра с наименьшим prod
writer.write("${segMin[1].idx + 1}")
writer.newLine()
}
}
}
writer.flush()
writer.close()
reader.close()
}