본문 바로가기

백준

C++[백준]2243번 사탕상자

https://www.acmicpc.net/problem/2243

 

2243번: 사탕상자

첫째 줄에 수정이가 사탕상자에 손을 댄 횟수 n(1 ≤ n ≤ 100,000)이 주어진다. 다음 n개의 줄에는 두 정수 A, B, 혹은 세 정수 A, B, C가 주어진다. A가 1인 경우는 사탕상자에서 사탕을 꺼내는 경우이

www.acmicpc.net

 

솔루션


처음에 특정 사탕을 꺼낼 방법을 고민을 했다.

 

그런데, 개수를 저장하는 세그먼트 트리를 구성하면, 

1부터 특정 맛 까지 총 몇개가 있는지 알 수 있다.

이 점을 이용해서 세그먼트 트리를 만들고, 세그먼트 트리를 갱신한다면 풀 수 있을 것이라 생각했다.

 

1) A가 1일 때, 사탕 상자에서 사탕을 빼내는 경우이기 때문에, 왼쪽노드는 더 맛있는 사탕이 있는 총 개수이다.

왼쪽 노드의 개수가 골라야 하는 개수보다 작거나 같을 때 왼쪽으로 가고, 왼쪽노드의 개수보다 큰 경우는 오른쪽으로 가되, 왼쪽 노드의 개수만큼 빼 준다.

그리고 각 노드에서는 사탕을 빼기 때문에 1을 빼준다.

 

2) 사탕상자에 C만큼 더해준다. 

 

 

 

코드


#define MAX 1000000
#include <iostream>
using namespace std;

int seg[4000002];
int N;

void updateSeg(int str, int end, int node, int idx, int val) {
	seg[node] += val;
	if (str == end) return;
	else {
		int mid = (str + end) / 2;
		if (idx <= mid) return updateSeg(str, mid, node * 2, idx, val);
		else return updateSeg(mid + 1, end, node * 2 + 1, idx, val);
	}
}

int getSeg(int str, int end, int node,int cnt) {
	seg[node]--;
	if (str == end) {
		return str;
	}
	else {
		int mid = (str + end) / 2;
		if (seg[node * 2] >= cnt) {
			return getSeg(str, mid, node * 2, cnt);
		}
		else {
			return getSeg(mid + 1, end, node * 2 + 1, cnt - seg[node * 2]);
		}
	}
}

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);

	cin >> N;
	while (N--) {
		int A, B, C;
		cin >> A >> B;

		//구간 합 배열?로  해결 가능?
		if (A == 1) { //사탕상자에서 사탕을 꺼내는 경우
			cout << getSeg(1, MAX, 1, B) << "\n";
		}
		else {//사탕 상자에 사탕을 넣거나 빼는 경우
			cin >> C;
			updateSeg(1, MAX, 1, B, C);
		}
	}
}

'백준' 카테고리의 다른 글

C++[백준]26004번 HI-ARC  (0) 2023.05.12
C++[백준]11670 초등 수학  (0) 2023.05.12
C++[백준]2244번 민코프스 합  (0) 2023.04.20
C++[백준]9345번 디지털 비디오 디스크(DVDs)  (2) 2023.04.20
C++[백준]3653번 영화 수집  (0) 2023.04.19