crowulll

Untitled

Nov 14th, 2021
1,015
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 20.18 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. // Я очень долго бился над этой задачей,
  4. // она много раз не сдавалась, так что в конце
  5. // в комментариях меня немного понесло,
  6. // но их суть точно должна быть понятна.
  7. // У меня будет 2 вида подмассивов - подмассив в куче
  8. struct subArrayHeap;
  9. // И его копия в двусвязном списке
  10. struct subArrayList;
  11. struct subArrayHeap {
  12.     // Всюду далее:
  13.     // l - левая граница подмассива,
  14.     // r - правая граница подмассива,
  15.     // левая и правая границы - обе включаются
  16.     long long l, r;
  17.     // Индекс подмассива в массиве,
  18.     // на котором реализована куча:
  19.     long long inx;
  20.     // Указатель на копию в двусвязном списке:
  21.     subArrayList* same_List;
  22.     subArrayHeap(long long new_l, long long new_r) {
  23.         l = new_l;
  24.         r = new_r;
  25.         inx = -1;
  26.         same_List = nullptr;
  27.     }
  28.     // Вычисляет длину подмассива
  29.     long long length() {
  30.         return this->r - this->l + 1;
  31.     }
  32.     // Перегрузка оператора >:
  33.     bool operator > (subArrayHeap *B) {
  34.         return (this->length() > B->length() || (this->length() == B->length() && this->l < B->l));
  35.     }
  36. };
  37.  
  38. // Для удобства, функция Max возвращает наибольший
  39. // подмассив из двух подмассивов, возможно благодаря перегрузке >
  40. subArrayHeap* Max(subArrayHeap* A, subArrayHeap* B) {
  41.     if (*A > B) {
  42.         return A;
  43.     } else {
  44.         return B;
  45.     }
  46. }
  47.  
  48. // Структура, опрерирующая с двусвязным списком:
  49. struct subArrayList {
  50.     long long l, r;
  51.     // Копия этого элемента в куче, если он свободен:
  52.     subArrayHeap* same_Heap;
  53.     // Указатель на подмассив, находящийся слева от данного:
  54.     subArrayList* Left;
  55.     // Указатель на подмассив, находящийся справа от данного
  56.     subArrayList* Right;
  57.     // Свободен или занят
  58.     bool empty;
  59.     subArrayList(long long new_l, long long new_r) {
  60.         l = new_l;
  61.         r = new_r;
  62.         Left = nullptr;
  63.         Right = nullptr;
  64.         same_Heap = nullptr;
  65.         empty = true;
  66.     }
  67.     // Аккуратное переписывание указателей,
  68.     // если решаем удалить подмассив насовсем из списка:
  69.     void kill() {
  70.         // Возможно переписать, только если слева что - то есть
  71.         if (this->Left) {
  72.             this->Left->Right = this->Right;
  73.         }
  74.         if (this->Right) {
  75.             this->Right->Left = this->Left;
  76.         }
  77.         delete this;
  78.     }
  79. };
  80.  
  81. // Делаем так, чтобы копия в 2-списке не указывала
  82. // на уничтоженный элемент кучи
  83. void killHeap(subArrayHeap* A) {
  84.     A->same_List->same_Heap = nullptr;
  85.     delete A;
  86. }
  87.  
  88. // Реализация кучи, где на макушке максимальный:
  89. struct Heap {
  90.     // Вектор, на котором она будет сидеть:
  91.     std::vector<subArrayHeap*> heap;
  92.     Heap() {
  93.         this->heap.resize(0);
  94.     }
  95.     // Показывает, сколько элементов в куче
  96.     long long sizeHeap() {
  97.         return this->heap.size();
  98.     }
  99.     // Дает информацию о том, пуста ли куча:
  100.     bool notEmpty() {
  101.         if (this->sizeHeap() == 0) {
  102.             return false;
  103.         } else {
  104.             return true;
  105.         }
  106.     }
  107.     // Для удобства возвращает указатель на макушку кучи
  108.     subArrayHeap* top() {
  109.         return this->heap[0];
  110.     }
  111.     // Возвращает указатель на родителя
  112.     subArrayHeap* Parent(subArrayHeap* A) {
  113.         if (A->inx == 0) {
  114.             return nullptr;
  115.         } else {
  116.             return heap[(A->inx - 1)/2];
  117.         }
  118.     }
  119.     // Возвращает указатель на левого ребенка:
  120.     subArrayHeap* LeftChild(subArrayHeap* A) {
  121.         if (2*(A->inx) + 1 >= this->sizeHeap()) {
  122.             return nullptr;
  123.         } else {
  124.             return this->heap[2*(A->inx) + 1];
  125.         }
  126.     }
  127.     // Возвращает указатель на правого ребенка:
  128.     subArrayHeap* RightChild(subArrayHeap* A) {
  129.         if (2*(A->inx) + 2 >= this->sizeHeap()) {
  130.             return nullptr;
  131.         } else {
  132.             return this->heap[2*(A->inx) + 2];
  133.         }
  134.     }
  135.     // Меняет 2 элемента кучи, аккуратно обходясь с параметром inx:
  136.     void SwapHeap(subArrayHeap* A, subArrayHeap* B) {
  137.         subArrayHeap* x = A;
  138.         long long inx_A = A->inx;
  139.         this->heap[A->inx] = B;
  140.         this->heap[B->inx] = x;
  141.         A->inx = B->inx;
  142.         B->inx = inx_A;
  143.     }
  144.     // Операция siftUp - обсуждалась на лекции
  145.     void siftUp(subArrayHeap* A) {
  146.         if (A->inx == 0) {
  147.             return;
  148.         }
  149.         if (*Parent(A) > A) {
  150.             return;
  151.         } else {
  152.             this->SwapHeap(A, this->Parent(A));
  153.             this->siftUp(A);
  154.         }
  155.     }
  156.     // Аналогично, обсуждалась на лекции
  157.     void siftDown(subArrayHeap* A) {
  158.         if (this->RightChild(A)) {
  159.             if (*Max(this->LeftChild(A), this->RightChild(A)) > A) {
  160.                 SwapHeap(Max(this->LeftChild(A), this->RightChild(A)), A);
  161.                 siftDown(A);
  162.             } else {
  163.                 return;
  164.             }
  165.         } else if (this->LeftChild(A)) {
  166.             if (*this->LeftChild(A) > A) {
  167.                 SwapHeap(A, this->LeftChild(A));
  168.                 siftDown(A);
  169.             } else {
  170.                 return;
  171.             }
  172.         }
  173.     }
  174.     // Чтобы удалить макушку, меняем его местами с последним элементом кучи,
  175.     // удаляем элемент из памяти, попаем вектор и
  176.     // получаем корректно построенную кучу
  177.     void killTop() {
  178.         SwapHeap(this->heap[0], this->heap[this->sizeHeap() - 1]);
  179.         killHeap(this->heap[this->sizeHeap() - 1]);
  180.         this->heap.pop_back();
  181.         this->siftDown(this->heap[0]);
  182.     }
  183.     // Чтобы удалить произвольный элемент из кучи,
  184.     // присваиваем ему космическую длину, siftUp
  185.     // гарантированно поднимет его на макушку,
  186.     // с помощью уже реализованного метода killTop():
  187.     void killAny(subArrayHeap* A) {
  188.         A->l = -1;
  189.         A->r = 2147483650;
  190.         this->siftUp(A);
  191.         this->killTop();
  192.     }
  193.     // Добавляем элемент списка в кучу:
  194.     void addHeap(subArrayList* B) {
  195.         // Создаем новый подмассив (В КУЧЕ)
  196.         auto* A = new subArrayHeap(B->l, B->r);
  197.         // Элемент списка должен указывать на кучу
  198.         B->same_Heap = A;
  199.         // А элемент кучи, в свою очередь - на список
  200.         A->same_List = B;
  201.         // Коли мы его добавили в куче,
  202.         // то он может быть пустым и никак иначе
  203.         B->empty = true;
  204.         // Кидаем его в кучу
  205.         this->heap.push_back(A);
  206.         // Говорим, что его индекс теперь самый правый
  207.         A->inx = this->sizeHeap() - 1;
  208.         // Поднимаем этот элементик:
  209.         siftUp(A);
  210.     }
  211. };
  212.  
  213. // Для удобства реализуем структуру запроса
  214. struct request {
  215.     // Это запрос на выделение памяти?
  216.     bool occupy;
  217.     // Получилось выделить память?
  218.     bool achieved;
  219.     // А где тот подмассив, который мы заняли на этом запросе
  220.     subArrayList* place;
  221.     request() {
  222.         this->occupy = false;
  223.         this->achieved = false;
  224.         this->place = nullptr;
  225.     }
  226. };
  227.  
  228. // Cтруктура менеджера:
  229. struct Manager {
  230.     // Даем ему в распоряжение кучу:
  231.     Heap H;
  232.     // N, M - из условий задачи
  233.     long long N, M;
  234.     // Менеджер памяти оперирует с запросами - логично держать его рядом
  235.     std::vector<request> req;
  236.     Manager(long long new_N, long long new_M) {
  237.         this->N = new_N;
  238.         this->M = new_M;
  239.         // Запросы нумеруются с единицы,
  240.         // так что пожертвуем ноликовым запросом - он никогда не будет использоваться
  241.         this->req.resize(M + 1);
  242.         // Создаем изначальный подмассив,
  243.         // который говорит, что все место пока свободно
  244.         auto* BIG = new subArrayList(1, N);
  245.         // Кидаем его в кучу:
  246.         this->H.addHeap(BIG);
  247.     }
  248.     // Выделение K памяти на r - том запросе
  249.     long long occupy(long long K, long long r) {
  250.         // Да, это запрос на выделение памяти
  251.         this->req[r].occupy = true;
  252.         if (this->H.notEmpty() && this->H.top()->length() >= K) {
  253.             // Куча непуста, на макушке хватает места,
  254.             // так что мы успешно выделили память
  255.             this->req[r].achieved = true;
  256.             // 1. На макушке ровно столько места, сколько нам сейчас надо:
  257.             if (this->H.top()->length() == K) {
  258.                 // Для удобства,
  259.                 // обозначаем указатель на макушку новой переменной place
  260.                 subArrayList* place = this->H.top()->same_List;
  261.                 // Теперь вся макушка занята
  262.                 this->H.top()->same_List->empty = false;
  263.                 // А в куче теперь уже ничего нет, так что указатель пустой
  264.                 this->H.top()->same_List->same_Heap = nullptr;
  265.                 // Удаляем его из кучи:
  266.                 H.killTop();
  267.                 // Мы заняли макушку кучи, так что скажем,
  268.                 // что на r - том запросе был занят подмассив place
  269.                 this->req[r].place = place;
  270.                 // Выведем левую границу подмассива, что и просили в условии
  271.                 return place->l;
  272.             // Если же вдруг надо занять не всю макушку:
  273.             } else {
  274.                 // Новый свободный подмассивчик new_free откололся от макушки,
  275.                 // как напоминание о том, что когда - то здесь было свободно.
  276.                 // Ну и, конечно, что он все еще свободен и может понадобиться
  277.                 auto* new_free = new
  278.                         subArrayList(this->H.top()->l + K, this->H.top()->r);
  279.                 // Урезаем макушку:
  280.                 this->H.top()->same_List->r = this->H.top()->same_List->l + K - 1;
  281.                 // Теперь макушка занята
  282.                 this->H.top()->same_List->empty = false;
  283.                 // Если справа от копии макушки в списке что - то есть,
  284.                 // то пусть он говорит, что слева от него теперь стоит new_free
  285.                 if (this->H.top()->same_List->Right) {
  286.                     this->H.top()->same_List->Right->Left = new_free;
  287.                     // А new_free скажет, что справа от него стоит тот, который стоял
  288.                     // когда - то справа от копии макушки в списке макушки
  289.                     new_free->Right = this->H.top()->same_List->Right;
  290.                 }
  291.                 // Теперь справа от копии макушки в списке стоит new_free
  292.                 this->H.top()->same_List->Right = new_free;
  293.                 // Слева от new_free теперь стоит копия макушки в списке
  294.                 new_free->Left = this->H.top()->same_List;
  295.                 // Теперь копия макушки в списке на кучу
  296.                 // даже смотреть не может после того, как стала занятой...
  297.                 this->H.top()->same_List->same_Heap = nullptr;
  298.                 // Теперь новый свободный подмассивчик new_free говорит макушке,
  299.                 // что он - все, что от нее осталось
  300.                 new_free->same_Heap = H.top();
  301.                 // Макушка соглашается с этим и говорит,
  302.                 // что new_free и она это одно и то же
  303.                 this->H.top()->same_List = new_free;
  304.                 // И стыдливо уменьшает свою длину до уровня new_free:
  305.                 this->H.top()->l = new_free->l;
  306.                 this->H.top()->r = new_free->r;
  307.                 // Теперь она стала меньше, и, возможно,
  308.                 // она теперь не самый большой свободный подмассивчик в куче.
  309.                 // Она жертвует своим высоким положением
  310.                 // и цена этой жертвы - корректно построенная куча.
  311.                 H.siftDown(this->H.top());
  312.                 // Теперь то, что стоит слева от
  313.                 // нового свободного подмассива - это то, что мы заняли
  314.                 this->req[r].place = new_free->Left;
  315.                 // Выводим то, что и хотят в задаче:
  316.                 return new_free->Left->l;
  317.             }
  318.         // Выделить память не получилось, так что выводим -1,
  319.         // параметры менять не надо в силу того, как определен конструктор
  320.         // в структуре запроса
  321.         } else {
  322.             return -1;
  323.         }
  324.     }
  325.     // Освобождение r - того запроса:
  326.     void release(long long r) {
  327.         // Получилось ли выделить память на r - том запросе?
  328.         if (this->req[r].achieved) {
  329.             // Также берем указатель на освобождаемый подмассив
  330.             // за новую переменную для удобства обращения:
  331.             subArrayList* place = this->req[r].place;
  332.             // 1. Слева и справа есть свободные подмассивы
  333.             if (place->Left && place->Right &&
  334.             place->Left->empty && place->Right->empty) {
  335.                 // Сохраняем указатель на то,
  336.                 // что стоит слева от освобождаемого в 2-списке:
  337.                 subArrayList* placeLeft = place->Left;
  338.                 // Растягиваем левый до уровня правого:
  339.                 place->Left->r = place->Right->r;
  340.                 // Удаляем в куче правый так как правый свободен:
  341.                 this->H.killAny(place->Right->same_Heap);
  342.                 // Удаляем правый в списке:
  343.                 place->Right->kill();
  344.                 // Удаляем освобождаемый в списке:
  345.                 place->kill();
  346.                 // Растягиваем левый и в куче тоже
  347.                 placeLeft->same_Heap->r = placeLeft->r;
  348.                 // Он стал больше, так что поднимем его в куче,
  349.                 // чтобы получить корректно построенную кучу:
  350.                 this->H.siftUp(placeLeft->same_Heap);
  351.             // 2. Cлева либо занято, либо ничего нет, справа свободный подмассив:
  352.             } else if (place->Right && place->Right->empty) {
  353.                 // Растягиваем то, что справа влево до уровня освобождаемого
  354.                 // (мы же их типа здесь сливаем)
  355.                 place->Right->l = place->l;
  356.                 // Изменяем и в куче тоже:
  357.                 place->Right->same_Heap->l = place->Right->l;
  358.                 // Он стал больше в куче, так что поднимаем его,
  359.                 // чтобы получить корректно построенную кучу:
  360.                 this->H.siftUp(place->Right->same_Heap);
  361.                 // Теперь тот, что был освобождаемый, стал ненужен,
  362.                 // так как его поглотил правый, можем его с чистой совестью уничтожить
  363.                 place->kill();
  364.             // 3. Справа либо ничего нет, либо занято, слева свободный подмассив:
  365.             } else if (place->Left && place->Left->empty) {
  366.                 // Ничем не отличается от предыдущего случаа,
  367.                 // то что происходит в 2. и 3. - суть одно и то же
  368.                 place->Left->r = place->r;
  369.                 place->Left->same_Heap->r = place->Left->r;
  370.                 this->H.siftUp(place->Left->same_Heap);
  371.                 place->kill();
  372.             // 4. Слева и справа либо ничего нет, либо занятые подмассивы:
  373.             } else {
  374.                 // Сливать теперь ничего не надо, так что просто говорим,
  375.                 // что освобождаемый подмассивчик таки свободен и закидываем его в кучу
  376.                 place->empty = true;
  377.                 H.addHeap(place);
  378.             }
  379.         }
  380.     }
  381.     // Реализованный для удобства метод чтобы обработать один запрос:
  382.     void Process_One_Request(long long T, long long r) {
  383.         // По условию, если поступает положительное число,
  384.         // то это запрос на выделение памяти
  385.         if (T > 0) {
  386.             std::cout << this->occupy(T, r) << std::endl;
  387.         // Если же отрицательное, то освобождение
  388.         } else {
  389.             this->release(-T);
  390.         }
  391.     }
  392.     // Также для удобства, но тут уже обрабатываются все M запросов:
  393.     void Process_All_Requests() {
  394.         for (int i = 1; i < M + 1; ++i) {
  395.             long long T;
  396.             std::cin >> T;
  397.             Process_One_Request(T, i);
  398.         }
  399.     }
  400. };
  401.  
  402. int main() {
  403.     long long N, M;
  404.     std::cin >> N >> M;
  405.     Manager Man(N, M);
  406.     Man.Process_All_Requests();
  407. }
  408.  
Advertisement
Add Comment
Please, Sign In to add comment