본문 바로가기
알고리즘/백준

[BOJ 12899] 데이터 구조(c++)

by umdoyun 2025. 12. 16.
728x90

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


문제 개요

자연수를 저장하는 데이터베이스 S에 대해 다음의 쿼리를 처리합니다.

  • 유형 1 : S에 자연수 X를 추가한다
  • 유형 2 : S에 포함된 숫자 중 X번째로 작은 수를 응답하고 그 수를 삭제한다.(S에 포함된 숫자는 X개 이상을 보장)

(1 ≤ N, X ≤ 2,000,000)


문제 풀이

이 문제는 원래 개수를 저장하는 세그먼트 트리와 이분 탐색을 통해 효율적으로 풀이 가능하지만, 바이너리 트라이로 해결하였습니다.

class node {
public:
	int cnt;
	node *child[2];
};

node pool[2000000 * 4];
node* root;
int p_cnt;

node* new_node() {
	pool[p_cnt].child[0] = nullptr;
	pool[p_cnt].child[1] = nullptr;
	return &pool[p_cnt++];
}

메모리 제한이 512MB로 매우 널널하니 메모리 풀로 최적화 하였습니다.

 

void insert(int x) {
	node* cur = root;
	for (int i = 21; i >= 0; i--) {
		cur->cnt++;
		int b;
		if (x & (1 << i)) {
			b = 1;
		}
		else {
			b = 0;
		}
		if (cur->child[b] == nullptr) {
			cur->child[b] = new_node();
		}	
		cur = cur->child[b];
	}
	cur->cnt++;
}

트라이에 값을 저장하는 함수입니다. x의 최대값이 200만이라 i를 21부터 탐색하였습니다. 몇 번째 수인지를 확인하기 위해 cnt를 넣었습니다.

int remove(int x) {
	node* cur = root;
	int ret = 0;
	for (int i = 21; i >= 0; i--) {
		cur->cnt--;
		int b;
		if (cur->child[0] && cur->child[1]) {
			if (cur->child[0]->cnt >= x) {
				b = 0;
			}
			else {
				x -= cur->child[0]->cnt;
				b = 1;
			}
		}
		else if (cur->child[0]) {
			b = 0;
		}
		else {
			b = 1;
		}
		ret |= (b << i);
		cur = cur->child[b];
	}
	cur->cnt--;
	return ret;
}

x번째 수를 찾아 제거하며 리턴하는 함수입니다.


코드

#include <iostream>
using namespace std;

class node {
public:
	int cnt;
	node *child[2];
};

node pool[2000000 * 4];
node* root;
int p_cnt;

node* new_node() {
	pool[p_cnt].child[0] = nullptr;
	pool[p_cnt].child[1] = nullptr;
	return &pool[p_cnt++];
}

void insert(int x) {
	node* cur = root;
	for (int i = 21; i >= 0; i--) {
		cur->cnt++;
		int b;
		if (x & (1 << i)) {
			b = 1;
		}
		else {
			b = 0;
		}
		if (cur->child[b] == nullptr) {
			cur->child[b] = new_node();
		}	
		cur = cur->child[b];
	}
	cur->cnt++;
}

int remove(int x) {
	node* cur = root;
	int ret = 0;
	for (int i = 21; i >= 0; i--) {
		cur->cnt--;
		int b;
		if (cur->child[0] && cur->child[1]) {
			if (cur->child[0]->cnt >= x) {
				b = 0;
			}
			else {
				x -= cur->child[0]->cnt;
				b = 1;
			}
		}
		else if (cur->child[0]) {
			b = 0;
		}
		else {
			b = 1;
		}
		ret |= (b << i);
		cur = cur->child[b];
	}
	cur->cnt--;
	return ret;
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int n;
	cin >> n;
	root = new_node();
	for (int i = 0; i < n; i++) {
		int cmd, x;
		cin >> cmd >> x;
		if (cmd == 1) {
			insert(x);
		}
		else {
			int ret = remove(x);
			cout << ret << '\n';
		}
	}
	return 0;
}

'알고리즘 > 백준' 카테고리의 다른 글

[BOJ 3002] 아날로그 다이얼(c++)  (0) 2025.12.30
[BOJ 12846] 무서운 아르바이트(c++)  (0) 2025.12.18
[BOJ 14446] Promotion Counting(c++)  (0) 2025.12.16
[BOJ 8308] Firm(c++)  (0) 2025.12.15
[BOJ 15899] 트리와 색깔(c++)  (0) 2025.12.15