Cod sursa(job #2546959)

Utilizator stormy_weatherelena cristina stormy_weather Data 14 februarie 2020 19:10:55
Problema Hotel Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 8.28 kb
#include<fstream>
#include<iostream>
#include<vector>
#include<set>
using namespace std;

void display_set(multiset<int> &free) {
  for (auto it = free.begin(); it != free.end(); ++it) {
    cout << *it << " ";
  }
  cout << "\n";
  return;
}

void delete_interval(multiset<int> &free, int a, int b) {
  //[a, b)
  int l = b - a;
  auto it = free.find(l);
  // if (it != free.end())
    free.erase(it);
  // else
  //   cout << "something went wrong trying to delete  from " << a << " to " << b << " \n";
}

void add_interval(multiset<int> &free, int a, int b) {
  //[a, b)
  int l = b - a;
  free.insert(l);
}

void add_interval(set <pair <int, int>> &busy, multiset <int> &free, int a, int b, int n) {
  // cout << "a is " << a << " and b is " << b << "\n";
  if (busy.empty()) {
    //we have no busy rooms presently
    delete_interval(free, 1, n + 1);
    busy.insert({a, b});
    if (a > 1)
      add_interval(free, 1, a);
    if (b < n + 1)
      add_interval(free, b, n + 1);
    return;
  }
  auto after = busy.lower_bound({b, 0});
  // cout << "after " << after->first << " " << after->second << "\n";
  if (after == busy.end()) {
    //we don't have a busy interval after our interval
    auto before = --after;
    // cout << "before is " << before->first << " " << before->second << "\n";
    //we delete the current empty space at the right
    delete_interval(free, before->second, n + 1);
    //and we add the new empty space at the right
    if (b < n + 1)
      add_interval(free, b, n + 1);

    //if the interval at the left is adjacent, we unite the intervals
    if (a == before->second) {
      int start = before->first;
      busy.erase(before);
      busy.insert({start, b});
    } else {
      //otherwise we add the new interval for busy rooms
      // and the gap between the interval to the left and the current interval
      busy.insert({a, b});
      add_interval(free, before->second, a);
    }
  } else if (after == busy.begin()) {
    //if there is no interval at the left, we delete the current gap
    delete_interval(free, 1, after->first);
    //and we add the new gap
    if (a > 1)
      add_interval(free, 1, a);

    //if the interval to the right is adjacent to this interval
    if (b == after->first) {
      //we delete the right interval and insert the merged one
      int end = after->second;
      busy.erase(after);
      busy.insert({a, end});
    } else {
      //otherwise we insert the new interval
      //and the new gap
      busy.insert({a, b});
      add_interval(free, b, after->first);
    }
  } else {
    //if there are neighbours on both sides, we get them
    auto before = after;
    --before;

    //we delete the current empty space
    delete_interval(free, before->second, after->first);

    int start = before->first, end = after->second;
    //if we want to insert an interval that fits the gap, we delete the neighbours and insert the merger
    if (a == before->second && b == after->first) {
      busy.erase(after);
      busy.erase(before);
      busy.insert({start, end});
    } else if (a == before->second) {
      //if the interval is adjacent only on the left
      //we delete the interval on the left and insert the merger
      //and we insert the right empty space
      busy.erase(before);
      busy.insert({start, b});

      add_interval(free, b, after->first);
    } else if (b == after->first) {
      //if the interval is adjacent only to the right
      //we delete the interval on the right and insert the merger
      //and we insert the left empty space
      busy.erase(after);
      busy.insert({a, end});

      add_interval(free, before->second, a);
    } else {
      //if the currentu interval isn't adjacent in any direction
      //we insert the new interval
      //and we insert the left and right empty spaces
      busy.insert({a, b});

      add_interval(free, before->second, a);
      add_interval(free, b, after->first);
    }
  }
  return;
}

void remove_interval(set <pair <int, int>> &busy, multiset <int> &free, int a, int b, int n) {
  //we get the first interval that comes after the right edge of the interval
  auto it = busy.lower_bound({b, 0});
  //and the interval from which we will do the erasing will be the one exactly before it
  auto busy_int = --it;
  //we keep in mind the limits for the parent interval that will be cut
  int start = busy_int->first, end = busy_int->second;

  int delete_start, delete_end;
  if (a == start && b == end) {
    //if we need to delete the whole interval, we determine where to make the cut
    if (busy_int == busy.begin()) {
      //if out interval doesn't have a neighbour to the left, we will delete from the first position
      delete_start = 1;
      //we delete the interval from 1 to the start because it will be replaced with the big empty interval
      if (a > 1)
        delete_interval(free, 1, a);
    } else {
      //if our interval has a neighbour to the left, the left limit for the cut will be where it ends
      //we delete the empty space between the interval because it will be replaced by the bigger one
      auto before = busy_int;
      --before;
      delete_start = before->second;
      delete_interval(free, before->second, a);
    }

    if (busy_int == --busy.end()) {
      //if the don't have an interval to the right, the edge will be n + 1
      //if we have an empty space to the right, we delete because it will be replaced by the big on
      delete_end = n + 1;
      if (b < n + 1)
        delete_interval(free, b, n + 1);
    } else {
      //if we have a neighbour to the right, the end will be there it starts
      //and we delete the empty space to the right, because it will be replaced by the big one
      auto after = busy_int;
      ++after;
      delete_interval(free, b, after->first);
      delete_end = after->first;
    }
    add_interval(free, delete_start, delete_end);
  } else if (a == start) {
    //if the interval matches the parent interval only on the left
    //we insert the remaining interval
    busy.insert({b, end});


    if (busy_int == busy.begin()) {
      //if we don't have a neighbour to the left, then we delete the small empty space
      //and we insert the bigger empty space, from 1 to b
      if (start > 1)
        delete_interval(free, 1, start);
      add_interval(free, 1, b);
    } else {
      //otherwise, we find the left neighbour and the delete the curent empty space and insert the new one
      auto before = busy_int;
      --before;
      delete_interval(free, before->second, a);
      add_interval(free, before->second, b);
    }

  } else if (b == end) {
    //if the interval matches the parent interval only on the right
    //we insert the left remaining interval
    busy.insert({start, a});

    if (busy_int == --busy.end()) {
      //if we don't have a neighbour to the right, we delete the current empty space
      //and insert the new one
      if (b < n + 1)
        delete_interval(free, b, n + 1);

      add_interval(free, a, n + 1);
    } else {
      //otherwise we get the right neighbour and we delete the current right empty space
      //and we insert the new right empty space
      auto after = busy_int;
      ++after;
      delete_interval(free, b, after->first);
      add_interval(free, a, after->first);
    }
  } else {
    //if the interval is smaller on both sides than the parent interval
    //we insert the remaining differences on both sides
    //and we insert the empty space between a and b
    busy.insert({start, a});
    busy.insert({b, end});
    add_interval(free, a, b);
  }

  //and we delete the parent interval because it has been replaced by the new bits
  busy.erase(busy_int);
  return;
}

int main() {
  ifstream fin("hotel.in");
  ofstream fout("hotel.out");

  int n, p; fin >> n >> p;

  set <pair <int, int>> busy;
  multiset <int> free;
  add_interval(free, 1, n + 1);

  for (int i = 0; i < p; i++) {
    int t; fin >> t;
    if (t == 3) {
      if (free.empty())
        fout << "0 \n";
      else {
        auto big = --free.end();
        fout << *big << "\n";
      }
    } else if (t == 1) {
      int a, b; fin >> a >> b;
      add_interval(busy, free, a, a + b, n);
      // cout << "dupa add \n";
      // display_set(free);
    } else if (t == 2) {
      int a, b; fin >> a >> b;
      remove_interval(busy, free, a, a + b, n);
      // cout << "dupa remove \n";
      // display_set(free);
    }
    // display_set(free);
  }

  return 0;
}