https://www.acmicpc.net/problem/8983
문제해설
이 문제는 "라인스위핑(line sweeping)" 알고리즘을 사용하여 해결 할 수 있습니다.
어떤 축을 기준으로 정렬한뒤에, 확인하는 경우의수를 대폭 줄일 수 있습니다.
많은 다른 블로그들은 lower_bound 없이 반복문으로 O(N)으로 풀으셨는데
lower_bound를 사용 하여 O(NlgN) 으로 풀었습니다.
풀이는 다음과 같습니다.
사대를 x축 정렬
동물들도 x축 정렬
정렬된 동물들을 처음부터 끝까지 탐색하는데
해당 동물이 사냥될 수 있는지 체크하기 위해서
해당 동물과 가장 오른쪽에서 가까운(x축기준) 사대
해당 동물과 가장 왼쪽에서 가까운(x축기준) 사대
를 찾아서 거리를 구해주면 됩니다.
lower_bound의 예외처리를 쉽게 하기 위해서 밑과 같은 사전처리를 해주었습니다.
sands.push_back(-MAX);
sands.push_back(MAX);
전체코드
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
using namespace std;
typedef long long ll;
vector<ll> sands;
vector<pair<ll, ll> > ani;
ll getDist(ll x, ll x1, ll y1) {
return abs(x - x1) + y1;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int M, N, L; cin >> M >> N >> L;
ll MAX = 1000000001;
for (int i = 0; i < M; i++) {
ll x; cin >> x;
sands.push_back(x);
}
for (int i = 0; i < N; i++) {
ll x, y; cin >> x >> y;
ani.push_back({ x,y });
}
sands.push_back(-MAX);
sands.push_back(MAX);
sort(sands.begin(), sands.end());
sort(ani.begin(), ani.end());
int ans = 0;
for (int i = 0; i < ani.size(); i++) {
ll x = ani[i].first;
ll y = ani[i].second;
auto left = lower_bound(sands.begin(), sands.end(), x);
auto right = left - 1;
if (min(getDist(*right, x, y), getDist(*left, x, y)) <= L) ans++;
}
cout << ans;
}