Strike Zone Optimization 문제는 특정 공간 내의 데이터를 분석하여 직사각형 ( R )의 최적 영역을 찾는 것이다. 주어진 두 점 집합 ( P1 ) (strike)과 ( P2 ) (ball)에 대해, 다음 평가 함수 ( \text{eval}(R) )를 최대화하는 직사각형 ( R )을 구하는 것이 목표다:
[
\text{eval}(R) = c1 \times s - c2 \times b
]
여기서:
#include <bits/stdc++.h>
using namespace std;
// 세그먼트 트리의 노드 구조체 정의
struct TreeNode {
long long sum, maxVal, leftMax, rightMax;
TreeNode() : sum(0), maxVal(0), leftMax(0), rightMax(0) { }
// 두 노드를 합치는 연산 정의
TreeNode operator+(TreeNode &other) {
TreeNode result;
result.sum = sum + other.sum;
result.leftMax = max(leftMax, sum + other.leftMax);
result.rightMax = max(other.rightMax, rightMax + other.sum);
result.maxVal = max(rightMax + other.leftMax, max(maxVal, other.maxVal));
return result;
}
};
// 세그먼트 트리 클래스 정의
struct RangeSegmentTree {
vector<TreeNode> nodes;
int size;
RangeSegmentTree(int n) {
int power = 1;
while (power < n) power *= 2;
nodes.resize(power * 2);
size = power;
}
void reset() {
nodes.clear();
nodes.resize(size * 2);
}
void update(int index, long long value) {
int current = index + size - 1;
nodes[current].sum += value;
nodes[current].leftMax += value;
nodes[current].rightMax += value;
nodes[current].maxVal += value;
while (current > 0) {
current = (current - 1) / 2;
nodes[current] = nodes[current * 2 + 1] + nodes[current * 2 + 2];
}
}
long long queryMax(int left, int right) {
left += size;
right += size + 1;
TreeNode leftResult, rightResult;
while (left < right) {
if (right & 1) {
--right;
rightResult = nodes[right - 1] + rightResult;
}
if (left & 1) {
leftResult = leftResult + nodes[left - 1];
++left;
}
left >>= 1;
right >>= 1;
}
return (leftResult + rightResult).maxVal;
}
};
// 좌표와 가중치를 저장하는 구조체 정의
struct Coordinate {
int x, y; long long weight;
Coordinate(int x, int y, long long weight) : x(x), y(y), weight(weight) { }
bool operator<(Coordinate &other) {
return y < other.y;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
vector<Coordinate> coordinates;
set<int> xCoords, yCoords;
unordered_map<int, int> xIndex, yIndex;
// P1 입력
int positiveCount;
cin >> positiveCount;
for (int i = 0; i < positiveCount; i++) {
int x, y;
cin >> x >> y;
xCoords.insert(x);
yCoords.insert(y);
coordinates.emplace_back(x, y, 1);
}
// P2 입력
int negativeCount;
cin >> negativeCount;
for (int i = 0; i < negativeCount; i++) {
int x, y;
cin >> x >> y;
xCoords.insert(x);
yCoords.insert(y);
coordinates.emplace_back(x, y, -1);
}
// 가중치 입력
long long weightPositive, weightNegative;
cin >> weightPositive >> weightNegative;
// 좌표 압축
int index = 0;
for (const auto& x : xCoords) xIndex[x] = index++;
index = 0;
for (const auto& y : yCoords) yIndex[y] = index++;
int xSize = xCoords.size();
int ySize = yCoords.size();
RangeSegmentTree segmentTree(xSize);
// 좌표 스윕 및 세그먼트 트리 계산
sort(coordinates.begin(), coordinates.end());
long long maximumValue = LLONG_MIN;
for (int i = 0; i < ySize; i++) {
segmentTree.reset();
for (const auto& point : coordinates) {
if (yIndex[point.y] < i) continue;
long long weight = (point.weight == 1 ? weightPositive : -weightNegative);
segmentTree.update(xIndex[point.x], weight);
maximumValue = max(maximumValue, segmentTree.queryMax(0, xSize - 1));
}
}
cout << maximumValue << '\n';
}
좌표 압축 및 데이터 준비
세그먼트 트리 초기화 및 업데이트
(y)축 스윕 및 최대값 계산
이 문제는 세그먼트 트리와 좌표 압축을 결합해 효율적으로 해결했다.
핵심은 2차원 좌표 공간에서 선형 시간 복잡도를 유지하며 최적의 평가 값을 찾는 것이다.
이 접근 방식은 데이터 분석 및 최적화 문제에서도 응용 가능성이 크다.