https://coderun.yandex.ru/problem/mobilization Средняя

Решение

import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter

// Класс дерева Фенвика для работы с Long-значениями.
class FenwickTree(val n: Int) {
    private val tree = LongArray(n + 1) { 0L }

    fun update(i: Int, delta: Long) {
        var idx = i
        while (idx <= n) {
            tree[idx] += delta
            idx += idx and -idx
        }
    }

    fun query(i: Int): Long {
        var sum = 0L
        var idx = i
        while (idx > 0) {
            sum += tree[idx]
            idx -= idx and -idx
        }
        return sum
    }

    // Находит минимальный индекс, такой что префиксная сумма >= target.
    fun lowerBound(target: Long): Int {
        var idx = 0
        var bit = Integer.highestOneBit(n)
        var curTarget = target
        while (bit > 0) {
            val next = idx + bit
            if (next <= n && tree[next] < curTarget) {
                curTarget -= tree[next]
                idx = next
            }
            bit = bit shr 1
        }
        return idx + 1
    }
}

fun main(args: Array<String>) {
    val reader = BufferedReader(InputStreamReader(System.`in`))
    val writer = BufferedWriter(OutputStreamWriter(System.out))
    
    // Читаем количество участников (n – четное)
    val n = reader.readLine().toInt()
    val K = n / 2  // нам нужно выбрать n/2 участников с наибольшими delta, что эквивалентно сумме n/2 наименьших для вычитания.
    
    // Читаем исходные значения навыков разработки и управления.
    val aList = reader.readLine().split(" ").map { it.toLong() }
    val bList = reader.readLine().split(" ").map { it.toLong() }
    
    // Глобальная сумма a[i] для вычисления ответа: answer = S_a - (сумма n/2 наименьших delta)
    var globalSumA = aList.sum()
    
    // Вычисляем для каждого участника начальное delta = a[i] - b[i].
    val diff = LongArray(n + 1)
    for (i in 1..n)
        diff[i] = aList[i - 1] - bList[i - 1]
    
    // Читаем количество запросов.
    val m = reader.readLine().toInt()
    // Сохраним все запросы, чтобы можно было собрать множество возможных значений diff.
    val queries = Array(m) {
        val parts = reader.readLine().split(" ")
        Triple(parts[0].toInt(), parts[1].toInt(), parts[2].toLong())
    }
    
    // Собираем множество candidate значений diff (начальные + все изменения).
    val allDiffs = ArrayList<Long>()
    for (i in 1..n)
        allDiffs.add(diff[i])
    val sim = diff.copyOf()
    for (q in queries) {
        val num = q.first
        val type = q.second
        val d = q.third
        if (type == 1) {
            sim[num] = sim[num] + d
        } else {
            sim[num] = sim[num] - d
        }
        allDiffs.add(sim[num])
    }
    
    // Координатное сжатие: получаем отсортированный список уникальных значений.
    allDiffs.sort()
    val compList = ArrayList<Long>()
    compList.add(allDiffs[0])
    for (i in 1 until allDiffs.size) {
        if (allDiffs[i] != compList.last())
            compList.add(allDiffs[i])
    }
    val compSize = compList.size
    // Создаем маппинг: значение -> позиция (1-индексировано)
    val compMap = HashMap<Long, Int>()
    for (i in compList.indices) {
        compMap[compList[i]] = i + 1
    }
    
    // Создаем два BIT-а: один для частот, другой для суммы.
    val bitFreq = FenwickTree(compSize)
    val bitSum = FenwickTree(compSize)
    
    // Инициализируем BIT’ы начальными значениями diff.
    for (i in 1..n) {
        val pos = compMap[diff[i]]!!
        bitFreq.update(pos, 1)
        bitSum.update(pos, diff[i])
    }
    
    // Функция для получения суммы K наименьших элементов diff из BIT.
    fun queryBottomK(k: Int): Long {
        // Находим минимальный индекс, такой что суммарная частота >= k.
        val idx = bitFreq.lowerBound(k.toLong())
        val countBefore = bitFreq.query(idx - 1)
        val sumBefore = bitSum.query(idx - 1)
        val remainder = k - countBefore
        val value = compList[idx - 1]
        return sumBefore + remainder * value
    }
    
    // После каждого запроса ответ вычисляется как: answer = globalSumA - (сумма n/2 наименьших diff).
    // (Заметим, что sum(a) - (сумма n/2 минимальных delta) равен суммарной пользе оптимального разделения.)
    val output = StringBuilder()
    for (q in queries) {
        val num = q.first
        val type = q.second
        val d = q.third
        // Удаляем старое значение diff[num] из BIT.
        val oldVal = diff[num]
        val oldPos = compMap[oldVal]!!
        bitFreq.update(oldPos, -1)
        bitSum.update(oldPos, -oldVal)
        
        // Обновляем diff и, если нужно, глобальную сумму a.
        if (type == 1) {
            diff[num] += d
            globalSumA += d
        } else {
            diff[num] -= d
        }
        val newVal = diff[num]
        val newPos = compMap[newVal]!!
        bitFreq.update(newPos, 1)
        bitSum.update(newPos, newVal)
        
        // Получаем сумму n/2 наименьших значений diff.
        val bottomSum = queryBottomK(K)
        val ans = globalSumA - bottomSum
        output.append(ans).append("\\n")
    }
    
    writer.write(output.toString())
    writer.flush()
    reader.close()
    writer.close()
}