Gym 100733 J Summer Wars 문제 풀이: 스캐닝 라인 을 활용 한 사상
n 개의 점, m 개의 가로 선 을 드 리 겠 습 니 다.너 는 이 선분 들 을 가로로 옮 길 수 있 지만, 이 선분 들 의 상대 적 인 위 치 는 바 꿀 수 없다.만약 에 한 점 이 그의 바로 위 와 바로 아래 에 모두 선분 (선분 의 종점 포함) 이 있다 면 이 점 은 '차단' 으로 간주 되 고 임 의 평 이 를 통 해 우리 가 가장 많은 점 을 가 릴 수 있 는 수량 을 물 었 다.
문제 풀이 방향:
먼저 모든 점 을 오른쪽으로 1000000 개의 단 위 를 평평 하 게 옮 긴 다음 에 그 선분 의 위치 가 변 하지 않 고 우 리 는 이 점 들 을 평평 하 게 옮 기기 시작 했다. 그러면 우 리 는 점 이 왼쪽으로 이동 하 는 거 리 는 반드시 양수 이 고 편리 하 게 처리 할 것 을 보증한다.
이렇게 해서 우 리 는 각 점 에서 왼쪽으로 이동 하 는 거 리 를 구 한 후에 문제 조건 을 만족 시 킬 수 있 는 집합 W 를 구 한 다음 에 특정한 거리 값 이 모든 집합 에서 가장 많은 횟수 를 나타 내 면 된다. 이 횟수 가 바로 답 이다.
우리 의 중점 은 이 집합 W 를 구 하 는 것 이다.만약 에 폭력 적 으로 찾 으 면 제목 의 데이터 범 위 는 1000000 이 고 포인트 가 1000 이 며 이들 의 상승 복잡 도 는 분명 불가능 하 다. 여기 서 우 리 는 스캐닝 라인 의 사상 을 활용 해 야 한다.
우 리 는 한 라인 을 두 개의 점 으로 본다. 입 점 과 출 점 이다.
예 를 들 어 (x1, y) - (x2, y) 의 선분 을 우 리 는 (x1, y) 의 위치 에 1 을 표시 하고 (x2 + 1, y) 의 위치 에 1 을 표시 한 다음 에 가로 좌표 에 따라 왼쪽 에서 오른쪽으로 이 점 들 을 훑 어 보 았 다. 사실은 선 을 스 캔 하 는 사상 이다. 그리고 실행 가능 한 범위 내 에서 우리 의 P 배열 위 치 를 + 1 한 다음 에 P 중의 최대 치 를 찾 으 면 된다.
여기 서 P 배열 을 업데이트 할 때 우 리 는 직접 폭력 적 으로 업데이트 할 수 없습니다. 예 를 들 어 우 리 는 구간 [l, r] 구간 을 모두 + 1 로 업데이트 하려 고 합 니 다. 우 리 는 P [l] 위치 에서 + 1, P [r + 1] 위치 에서 - 1 을 업데이트 한 다음 에 마지막 에 같이 업데이트 하면 됩 니 다.
코드 는 다음 과 같 습 니 다:
#include <bits/stdc++.h>
using namespace std;
int N, M;
pair<int, int> A[1000]; //
struct event { // ,tp = 1 ,tp = -1
int x, y, tp;
bool operator< (const event& other) const {
return x < other.x;
}
};
event B[2015];
int P[2000016]; //
int main() {
//freopen("in.in", "r", stdin);
//freopen("out.out", "w", stdout);
scanf("%d%d", &N, &M);
for (int i = 0; i < N; i++) {
scanf("%d%d", &A[i].second, &A[i].first); // , y,x
A[i].first += 1000000;
}
int y, x1, x2;
for (int i = 0; i < M; i++) {
scanf("%d%d%d", &y, &x1, &x2);
B[i * 2] = (event) {x1, y, 1};
B[i * 2 + 1] = (event) {x2 + 1, y, -1};
}
sort(B, B + 2 * M); //
multiset<int> s; s.clear(); //s
for (int i = 0; i < N; i++) {
int last = -1;
for (int j = 0, k; j < 2 * M; j = k) {
for (k = j; k < 2 * M && B[k].x == B[j].x; k++) {
if (B[k].tp == -1)
s.erase(s.find(B[k].y));
else
s.insert(B[k].y);
}
if (last != -1) P[A[i].first - B[j].x + 1]++, P[A[i].first - last + 1]--; //O(1) P
if (s.empty() || *s.begin() > A[i].second || *s.rbegin() < A[i].second) // i
last = -1;
else
last = B[j].x; //
}
}
int ans = 0;
for (int i = 1; i <= 2000015; i++)
ans = max(ans, P[i] += P[i - 1]); // ,
printf("%d
", ans);
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
정수 반전Udemy 에서 공부 한 것을 중얼거린다 Chapter3【Integer Reversal】 (예) 문자열로 숫자를 반전 (toString, split, reverse, join) 인수의 수치 (n)가 0보다 위 또는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.