Задача
Черный Ящик представляет собой примитивную базу даных. Он может хранить массив целых чисел, а также имеет специальную переменную $i$. В начальный момент Черный Ящик пустой, переменная $i$ равна $0$. Черный Ящик обрабатывает последовательность команд (транзакций). Существует два типа транзакций:
ADD(x): добавить элемент x в Черный Ящик;
GET: увеличить $i$ на $1$ и вывести $i$-ый минимальный элемент среди всех чисел, находящихся в Черном Ящике.
Помните, что $i$-ый минимальный элемент находится на $i$-ом месте после того как все элементы Черного Ящика будут отсортированы в неубывающем порядке.
Рассмотрим работу черного ящика на примере:
№
|
Транзакция
|
$i$
|
Содержимое Черного Ящика после транзакции
|
Ответ
|
1
|
ADD(3)
|
0
|
3
|
|
2
|
GET
|
1
|
3
|
3
|
3
|
ADD(1)
|
1
|
1, 3
|
|
4
|
GET
|
2
|
1, 3
|
3
|
5
|
ADD(-4)
|
2
|
-4, 1, 3
|
|
6
|
ADD(2)
|
2
|
-4, 1, 2, 3
|
|
7
|
ADD(8)
|
2
|
-4, 1, 2, 3, 8
|
|
8
|
ADD(-1000)
|
2
|
-1000, -4, 1, 2, 3, 8
|
|
9
|
GET
|
3
|
-1000, -4, 1, 2, 3, 8
|
1
|
10
|
GET
|
4
|
-1000, -4, 1, 2, 3, 8
|
2
|
11
|
ADD(2)
|
4
|
-1000, -4, 1, 2, 2, 3, 8
|
|
Необходимо разработать эффективный алгоритм выполнения заданной последовательности транзакций. Максимальное количество транзакций ADD и GET равно $30000$ (каждого типа).
Опишем последовательность транзакций двумя целочисленными массивами:
- $A_1, \ A_2, \ldots , \ A_m:$ последовательность элементов, которая будет добавляться в Черный Ящик. Элементами являются целые числа, по модулю не большие $2 000 000 000$, $m \leq 30000$. Для выше описанного примера $A = \left (3, 1, -4, 2, 8, -1000, 2 \right).$
- $u_1, \ u_2, \ldots, \ u_n:$ последовательность указывает на количество элементов в Черном Ящике в момент выполнения первой, второй, … $n$-ой транзакции GET. Для выше описанного примера $u = \left (1, 2, 6, 6 \right ).$
Работа Черного Ящика предполагает, что числа в последовательности $u_1, \ u_2, \ldots , \ u_n$ отсортированы в неубывающем порядке, $n \leq m$, а для каждого $p \left (1 \leq p \leq n \right )$ имеет место неравенство $p \leq u(p) \leq m$. Это следует из того, что для $p$-го элемента последовательности $u$ мы выполняем GET транзакцию, которая выводит $p$-ый минимальный элемент из набора чисел $A_1, \ A_2, \ldots , \ A_{u_p}$.
Входные данные
Состоит из следующего набора чисел: $m, \ n, \ A_1, \ A_2, \ldots , \ A_m, \ u_1, \ u_2, \ldots , \ u_n.$ Все числа разделены пробелами и (или) символом перевода на новую строку.
Выходные данные
Вывести ответы Черного Ящика на последовательность выполненных транзакций. Каждое число должно выводиться в отдельной строке.
Тесты
Входные данные |
Выходные данные |
7 4
3 1 -4 2 8 -1000 2
1 2 6 6
|
3
3
1
2
|
8 3
5 8 3 7 3 5 7 0
2 3 3 |
5
5
8
|
10 4
6 3 7 3 8 4 7 4 6 15
4 6 8 9
|
3
3
4
4
|
5 5
1 2 3 4 5
1 2 3 4 5
|
1
2
3
4
5
|
11 5
4 6 8 9 5 3 6 8 10 12 13
6 7 8 9 10
|
3
4
5
6
6
|
Код программы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Map; import java.util.Scanner; import java.util.TreeMap; public class Main { public static void main(String[] args) throws Exception{ Scanner sc = new Scanner(System.in); int m = sc.nextInt(); int n = sc.nextInt(); int[] nums = new int[m]; for(int i = 0; i < m; i++){ nums[i] = sc.nextInt(); } TreeMap<Integer, Integer> blackBox = new TreeMap<>(); blackBox.put(Integer.MAX_VALUE, 1); int size = 1; int curKey = Integer.MAX_VALUE; int curValue = 1; int curPosition = 0; for(int i = 0; i < n; i++){ int req = sc.nextInt(); for(int j = size - 1; j < req; j++){ if (blackBox.containsKey(nums[j])) { blackBox.put(nums[j], blackBox.get(nums[j]) + 1); if (curKey == nums[j]) { curValue++; } } else { blackBox.put(nums[j], 1); } if(nums[j] < curKey) { if (curPosition == 0) { Map.Entry<Integer, Integer> curEnrty= blackBox.lowerEntry(curKey); curKey = curEnrty.getKey(); curValue = curEnrty.getValue(); curPosition = curValue - 1; } else { curPosition--; } } } size = req + 1; System.out.println(curKey); if (curPosition == curValue - 1) { Map.Entry<Integer, Integer> curEnrty = blackBox.higherEntry(curKey); curKey = curEnrty.getKey(); curValue = curEnrty.getValue(); curPosition = 0; } else { curPosition++; } } } } |
Решение задачи
В следствие того, что в JCF нет мультисета, реализуем необходимые нам его функции (а именно итерирование) на базе
TreeSet, ключами которого будут уникальные значения, хранящиеся в черном ящике, а значениями — количество раз, которое это значение содержится в черном ящике. При чтении очередного запроса добавляем соответствующие элементы в черный ящик, итерируясь вниз в случае добавления меньшего элемента чем текущий, и итерируемся вверх после каждого запроса.
Ссылки
Условие задачи на e-olymp
Решение на e-olymp
Код решения на Ideone