BOJ 백준 5676 : 음주 코딩
Updated:
시작하면서
이번 문제는 세그먼트 트리(Segment Tree) 문제이다.
문제 이해
이 문제는 기본적인 세그먼트 트리 문제와 틀이 같다. 하지만 다음 두 가지를 주의해야 한다.
- 답을 출력할 때에는 숫자와 관계 없이 양수, 음수, 0 인지에 대해서만 묻는다.
- 수열의 크기가 10^5 이므로 다짜고짜 전부 곱해서 저장하면 100^(10^5) 곱해야 하므로 자료형이 감당이 안 된다.
위 두 가지 이유로 이 문제는 인풋을 받을때 양수면 1로, 음수면 -1로 치환해서 사용한다. 만약 1과 -1이 아니었으면 0을 곱했다가 값을 바꾸어 줄 때 로직이 복잡해지겠지만 다행히 1과 -1이므로 무시하고 덧셈, 뺄셈 세그먼트 트리처럼 진행하면 답이 나온다.
해결
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 1. 배열의 인덱스 번호는 1부터 시작
// 2. 왼쪽 자식은 2 * index
// 3. 오른쪽 자식은 2 * index + 1
int InitSegmentTree(vector<int>& arr, vector<int>& segmentTree, int node, int start, int end)
{
// 현재 노드가 리프 노드인 경우, 배열의 그 원소를 가져야 함
if (start == end)
return segmentTree[node] = arr[start];
int mid = (start + end) * 0.5f;
int left = InitSegmentTree(arr, segmentTree, node * 2, start, mid);
int right = InitSegmentTree(arr, segmentTree, node * 2 + 1, mid + 1, end);
segmentTree[node] = left * right;
return segmentTree[node];
}
int UpdateSegmentTree(vector<int>& segmentTree, int node, int start, int end, int index, int diff)
{
// 1. [start, end]에 index가 포함되지 않는 경우
if (start > index || end < index)
return segmentTree[node];
if (start == end)
return segmentTree[node] = diff;
// 리프 노드가 아닌 경우 자식도 변경해주어야 하기 때문에,
// 리프 노드인지 검사를 하고 아래 자식 노드를 갱신해준다.
int mid = (start + end) * 0.5f;
int l = UpdateSegmentTree(segmentTree, node * 2, start, mid, index, diff);
int r = UpdateSegmentTree(segmentTree, node * 2 + 1, mid + 1, end, index, diff);
return segmentTree[node] = l * r;
}
int QuerySegmentTree(vector<int>& segmentTree, int node, int start, int end, int left, int right)
{
// 1. [start, end] 앞 뒤에 [left, right]가 있는 경우
if (left > end || right < start)
return 1;
// 2. [start, end]가 [left, right]에 포함되는 경우
if (left <= start && end <= right)
return segmentTree[node];
// 3. 나머지 경우
int mid = (start + end) * 0.5f;
int l = QuerySegmentTree(segmentTree, node * 2, start, mid, left, right);
int r = QuerySegmentTree(segmentTree, node * 2 + 1, mid + 1, end, left, right);
int result = l * r;
return result;
}
void ConvertValue(int* value)
{
if (*value > 0)
{
*value = 1;
}
else if (*value < 0)
{
*value = -1;
}
}
int main()
{
// sync off
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// sync off
vector<int> segmentTree;
vector<int> numbers;
int n, k;
while (cin >> n)
{
cin >> k;
segmentTree.resize(n * 4);
numbers.resize(n + 1);
for (int i = 1; i < n + 1; i++)
{
cin >> numbers[i];
ConvertValue(&numbers[i]);
}
// make segment tree
InitSegmentTree(numbers, segmentTree, 1, 1, n);
for (int i = 0; i < k; i++)
{
char order;
int v, w;
cin >> order >> v >> w;
if (order == 'C')
{
ConvertValue(&w);
UpdateSegmentTree(segmentTree, 1, 1, n, v, w);
}
else if (order == 'P')
{
int result = QuerySegmentTree(segmentTree, 1, 1, n, v, w);
if (result == 0)
{
cout << "0";
}
else if (result > 0)
{
cout << "+";
}
else
{
cout << "-";
}
}
}
cout << "\n";
}
return 0;
}
Leave a comment