/*
* Problem :: 11000 / 강의실 배정
*
* Kind :: Greedy + Data Structure
*
* Insight
* - 일단 주어지는 수업들을 정렬해야 한다
* 빨리 시작하고, 같이 시작한다면 빨리 끝나는 순서대로 수업들을 정렬한다
* + 최소의 강의실을 사용해서 수업들을 모두 가능하게 해야 하는데...
* 각 강의실이 진행하고 있는 수업의 시작 시간과 종료 시간을 추적해야 한다
* # 그런데 일단 수업이 시작하면 그 수업의 종료 시간만 알아도
* 다른 수업이 가능한지 알 수 있으므로 시작 시간까지는 추적할 필요가 없다
* -> 또한 각 강의실이 진행하고 있는 수업 중 가장 빨리 끝나는 수업의 시간만 알아도
* 다음 수업이 현재 강의실만으로 가능한지 알 수 있다
* => 현재 강의실이 진행하고 있는 수업 중 가장 빨리 끝나는 수업의 시간이
* 다음 수업이 시작하는 시간보다 같거나 작다면 다음 수업을 시작할 수 있고
* 그렇지 않다면 다음 수업이 불가능하므로 강의실을 하나 더 늘려야 한다!
*
* - 항상 가장 빨리 수업이 끝나는 강의실을 알고 있어야 한다
* + 우선순위 큐를 활용하자!
* # 각 강의실에 번호를 붙여야 하는 것도 아니고 전체 강의실의 수만 알면 되므로
* 강의실이 진행하고 있는 수업의 종료 시간만 저장해주자
* -> priority<int,vector<int>,greater<>> <= Min Heap
* int <= 수업 종료 시간
*
* Point
* - less(default) 정렬에는
* operator < 가 정의되어 있어야 한다 <= 첫번째 인자를 기준으로 비교(<) 한다
* greater 정렬에는
* operator > 가 정의되어 있어야 한다 <= 첫번째 인자를 기준으로 비교(>) 한다
* + 우선순위 큐에서는 Min Heap 에는 greater 정렬이
* Max Heap 에는 less 정렬이 사용된다
* # 사실 좀 헷갈린다...
* Min Heap 에는 less 정렬이, Max Heap 에는 greater 정렬이 되야되는거 아닌가?
* -> 공식문서
* A priority queue is a container adaptor
* that provides constant time lookup of the largest (by default) element,
* at the expense of logarithmic insertion and extraction.
* A user-provided Compare can be supplied to change the ordering,
* e.g. using std::greater<T> would cause the smallest element
* to appear as the top().
* => 그렇다고 합니다...
*/
//
// BOJ
// ver.C++
//
// Created by Rainy
//
// Open Source
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
#define endl '\n'
// Set up : Global Variables
struct Course { int s, t; };
// Set up : Functions Declaration
bool operator < (Course u, Course v);
int main()
{
// Set up : I/O
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Set up : Input
int N; cin >> N;
vector<Course> C(N);
for (int i=0; i<N; i++)
cin >> C[i].s >> C[i].t;
// Process
sort(C.begin(), C.end()); /* 빨리 시작하고 빨리 끝나는 순서대로 수업들 정렬 */
/* 각 강의실 수업 종료 시간을 저장하는 우선순위 큐 */
priority_queue<int,vector<int>,greater<>> R;
R.push(0); /* 수업이 있다면 최소 1개의 강의실은 있어야 함 */
for (int i=0; i<N; i++) {
int s = C[i].s; /* i 번째 수업의 시작 시간 */
int t = C[i].t; /* i 번째 수업의 종료 시간 */
/* 강의실 중 가장 빨리 끝나는 수업의 종료 시간이 i 번째 수업의 시작 시간보다 빠르다면 */
if (R.top() <= s) { /* 그 강의실을 i 번째 수업을 하는 강의실로 만듦 */
R.pop(); /* 다만, R.top(0 = t 처럼
* R.top() 의 값을 바로 바꿀 수 없으므로 */
R.push(t); /* R.pop() 하고, R.push(t) 해주는 방식으로 정보를 갱신함 */
}
/* 강의실 중 가장 빨리 끝나는 수업의 종료 시간이 i 번째 수업의 시작 시간보다 느리다면 */
else { R.push(t); } /* i 번째 수업을 하는 강의실을 추가 */
}
// Control : Output
cout << R.size() << endl;
}
// Helper Functions
bool operator < (Course u, Course v)
/* Course 구조체를 정렬하기 위한 연산자 오버로딩 */
{
return make_pair(u.s, u.t) < make_pair(v.s, v.t);
}