[13334] 철로

2022. 3. 5. 21:41·PS | CP/Baekjoon OJ
 

13334번: 철로

입력은 표준입력을 사용한다. 첫 번째 줄에 사람 수를 나타내는 양의 정수 n (1 ≤ n ≤ 100,000)이 주어진다. 다음 n개의 각 줄에 정수 쌍 (hi, oi)가 주어진다. 여기서 hi와 oi는 −100,000,000이상, 100,000,0

www.acmicpc.net

많은 블로그들에서는 Priority Queue를 사용하는 해설을 적어 놓았고 사실 Priority Queue를 쓰는 게 낫긴 한데, 여기서는 Priority Queue를 안 쓰는 방식을 소개한다.

문제의 철로 L의 오른쪽 끝과 수직선 상에 존재하는 가장 왼쪽의 건물이 처음 만날 때부터 왼쪽 끝이 가장 오른쪽의 건물을 지날 때까지 이동한다고 생각하자. 이 상황을 L이 움직임에 따라 각 건물이 L에 추가되었다가 제거되는 것으로 해석할 수 있다.


철로의 오른쪽 끝은 만나는 모든 건물을 L 안에 추가한다.
철로의 왼쪽 끝은 만나는 모든 건물을 L 밖으로 제거한다.

이렇게 L에 건물을 추가하고 제거하는 행동을 해야 하는 '이벤트'를 생각하자. 어떠한 이벤트가 발생할 때 철로의 시작 위치를 이벤트 발생 지점이라고 하면, 각 건물의 위치 $p_b$에 따른 이벤트 발생 지점 $p_e$는 다음과 같다.

건물 추가 : $p_e = p_b - d$
건물 제거 : $p_e = p_b$

 

이 문제에서 고려하여야 할 사항은 지정된 한 쌍의 건물이 모두 L 안에 포함되는 경우를 세어야 한다는 것이고, 이는 이벤트에 특정한 tag를 달아 추가 이벤트가 발생할 때에 arr[tag] += 1, 제거 이벤트가 발생할 떄에 arr[tag] -= 1을 해 준다면 arr[tag]가 2일 경우 카운트하는 방식으로 해결할 수 있다.

 

또 삭제 이벤트의 경우 이벤트가 발생된 해당 건물이 즉시 삭제되는 것이 아니라 그 다음 이벤트가 발생하기 직전에 삭제되어야 하고, 같은 위치에서 여러 이벤트가 발생된 경우 동시에 처리되어야 한다.

struct event {
    int loc;
    int tag;
    bool add;
};

vector<pair<int, int>> tmpp;
vector<event> events;

int c[100001];

int main() {
    fastio;
    
    int N;
    cin >> N;
    for(int i = 0; i < N; i++) {
    	int b1, b2;
        cin >> b1, b2;
        tmpp.push_back({b1, b2});
    }
    int d;
    cin >> d;
    for(int i = 0; i < N; i++) {
        int b1 = tmpp[i].first;
        int b2 = tmpp[i].second;
        events.push_back({ b1 - d, i, true });
        events.push_back({ b1, i, false });

        events.push_back({ b2 - d, i, true });
        events.push_back({ b2, i, false });
    }

    sort(events.begin(), events.end(), [](event& a, event& b) {
        return a.loc < b.loc;
        });

    int i = 0;
    int cnt = 0;
    int mcnt = -1;
    while (i < events.size()) {
        int j = i;
        int loc = events[i].loc;
        while (j < events.size() && events[j].loc == loc) {
            if (events[j].add)
                if (++c[events[j].tag] == 2) cnt++;
            j++;
        }
        if (mcnt < cnt) mcnt = cnt;
        while (i < j) {
            if (!events[i].add)
                if (c[events[i].tag]-- == 2) cnt--;
            i++;
        }
    }

    cout << mcnt;
    return 0;
}​

 

'PS | CP/Baekjoon OJ' 카테고리의 다른 글
  • [17378] 공의 합집합
  • [16140] 정수론과 응용
  • [2731] 1379와 세제곱
  • [20500] Ezreal 여눈부터 가네 ㅈㅈ
SafeSpot
SafeSpot
  • SafeSpot
    SafeSpot::SafePost
    SafeSpot
    contact : me@safespot.dev
    BOJ | solved.ac | CF | Git
  • 전체
    오늘
    어제
    • 분류 전체보기 (60)
      • 아무거나 (11)
      • 수학 (2)
      • 프로그래밍 (1)
      • PS | CP (45)
        • CF | Atcoder (10)
        • Baekjoon OJ (35)
      • 소프트웨어 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 인기 글

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
SafeSpot
[13334] 철로
상단으로

티스토리툴바