티스토리 뷰
[BOJ 10167]금광 - D5
문제 설명
2차원 좌표평면상에서 [x좌표,y좌표,가중치]가 한 세트로 이루어진 정보가 N개 주어진다. 우리는 이 좌표평면 상에서 적당한 직사각형을 만들어서 그 직사각형 내부에 있는 가중치가 최대가 되도록 만들면 된다.
문제 풀이
2차원 좌표평면이 나오므로 일단 하나의 축을 기준으로 정렬하고 라인스위핑으로 푸는 방법을 생각했다. y좌표를 오름차순으로 먼저 정렬해놓고, x좌표를 컨트롤 하면 될 것 같다. (반대로 해도 상관없다)
이 문제의 경우에는 먼저 직사각형의 바닥과 천장(y좌표)를 픽스해둔 상태에서, 그 범위 안에 들어오는 x좌표를 왼쪽 -> 오른쪽 방향으로 쭉 저장해놓는다. 이렇게 하고 나면 이 문제를 '가장 큰 연속하는 부분수열의 합' 문제로 바꿀 수 있게 된다. 그렇다면 '가장 큰 연속하는 부분수열의 합'은 어떻게 구할까?
여기선 4개의 배열이 필요하다. 2진트리의 형태로 구성한다고 할 때
원소의 총합(sum), 왼쪽 자식의 최대값(lMax), 오른쪽 자식의 최대값(rMax), 전체의 최대값(totalMax)
가 필요하다.
그래서 각 segment가 합쳐질 때 필요한 연산이 아래 첨부한 소스코드 update()함수의 while문 안에 들어있다.
이 연산 과정을 통해 최종적으로 '가장 큰 연속하는 부분수열의 합'은 totalMax[1] 값에 들어있게 된다. 이 과정을 직사각형의 바닥과 천장을 2중 for문을 활용하여 모든 케이스에 대해 조사하여 그 중에서 가장 큰 가중치의 합을 찾으면 된다.
비슷한 문제
금광 문제에서 '가장 큰 연속하는 부분수열의 합' 부분만 똑 떼어내면 아래 문제처럼 된다.
소스 코드
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int SIZE = 3009;
ll totalMax[SIZE*8],lMax[SIZE*8],rMax[SIZE*8],sum[SIZE*8];
map<int,int> xComp,yComp;
map<int,vector<pii>> yCord;
vector<int> yVec;
int n,startIdx=1;
void update(int node,int k){
node = node + startIdx - 1;
lMax[node] += k;
rMax[node] += k;
sum[node] += k;
totalMax[node] += k;
node /= 2;
while(node >= 1){
int lCh = node*2,rCh = node*2+1;
sum[node] = sum[lCh] + sum[rCh];
lMax[node] = max(lMax[lCh], sum[lCh] + lMax[rCh]);
rMax[node] = max(rMax[rCh], sum[rCh] + rMax[lCh]);
totalMax[node] = max({totalMax[lCh], totalMax[rCh], rMax[lCh] + lMax[rCh]});
node /= 2;
}
}
void clear(){
for(int i=0 ; i<=startIdx * 2 ; i++){
sum[i] = lMax[i] = rMax[i] = totalMax[i] = 0;
}
}
int main(){
scanf("%d",&n);
for(int i=1 ; i<=n ; i++){
int a,b,w; scanf("%d %d %d",&a,&b,&w);
xComp[a] = yComp[b] = 1;
yCord[b].push_back({w,a});
}
int xCnt = 1;
for(auto &here : xComp){
here.second = xCnt++;
}
int yCnt = 1;
for(auto &here : yComp){
here.second = yCnt++;
yVec.push_back(here.first);
}
for(;startIdx < xCnt - 1 ; startIdx *= 2);
ll ans = 0;
for(int i=0 ; i<yCnt-1 ; i++){
clear();
for(int j=i ; j<yCnt-1 ; j++){
for(auto &here : yCord[yVec[j]]){
int w = here.first,x = here.second, idx = xComp[x];
update(idx,w);
}
ll cur = totalMax[1];
ans = max(ans, cur);
}
}
printf("%lld\n",ans);
return 0;
}
'Problem Solving > Segment Tree' 카테고리의 다른 글
[BOJ 3392] 화성 지도 (0) | 2022.01.26 |
---|---|
[BOJ 15899]트리와 색깔 (0) | 2021.11.16 |
[BOJ 2820] 자동차 공장 (0) | 2021.11.16 |
[BOJ 2912]백설공주와 난쟁이 (0) | 2021.11.13 |
[BOJ 11658]구간 합 구하기3 (0) | 2021.11.13 |
댓글