출처 : https://www.acmicpc.net/problem/10775

한 6개월전 union-find 분류 훑다가 문제 이해가 안대서 넘겼는데

오늘 다시 보니깐 union-find풀이방법은 생각 안나고 이상하게 segment tree풀이가 생각났다.

간단한 설명 :
i번째 비행기가 k번쨰 게이트에 도킹하고 싶다.
지금 k번째 게이트가 비어 있다면 도킹하면 된다.

그러나 k번쨰 게이트가 이미 도킹된 상태라면
1 ~ k - 1번쨰 게이트에 세우면 되는데 되도록 큰 숫자를 가지는 게이트에 세워야 한다.
(미안... 솔직히 증명은 몬하겠는데 사실 이러면 안되는데 직관이 넘 쎄게 들어옴..)

그래서 내가 새로 도킹할 게이트 번호를 p라 하자
p를 구하기 위해서는 우선 1 ~ k - 1 까지 비어있는 게이트 수를 구하자
(여기서 비어있는 게이트 수를 s라 하자)

만약 s가 0 이면 더이상 세울 수 있는 게이트의 수가 0이니 종료를 하고

0이 아니라면 비어있는 게이트중 s번째 비어있는 게이트를 찾으면 된다.

말이 좀 어색한데 코드를 보면 이해가 될것이다.

#include<stdio.h>
#include<malloc.h>
int answer, *tree, *list;
int make_answer();
int qu(int, int, int, int, int);
void update(int);
int kth(int, int, int, int);
int main(void)
{
	answer = make_answer();
	printf("%d\n", answer);
	return 0;
}
int make_answer()
{
	int gn, an, i, node, s, e, l, r, g, t, ans, idx;
	scanf("%d", &gn);
	scanf("%d", &an);
	for (i = 0, list = (int *)malloc(sizeof(int) * an); i < an; i++)
	{
		scanf("%d", &list[i]);
	}
	for (node = s = l = r = 1; r - l + 1 < gn; l <<= 1, r <<= 1, r |= 1);
	for (tree = (int *)calloc(r + 1, sizeof(int)), g = l - 1, e = r - l + 1, i = l; i <= r; i++)
	{
		tree[i] = 1;
	}
	for (i = g; i; i--)
	{
		tree[i] = tree[i << 1] + tree[i << 1 | 1];
	}
	for (i = ans = 0; i < an; i++)
	{
		t = list[i];
		if (tree[g + t] == 1)
		{
			ans++;
			update(g + t);
			continue;
		}
		t = qu(node, s, e, 1, t - 1);
		if (t)
		{
			ans++;
			idx = kth(node, s, e, t);
			update(idx + g);
		}
		else
		{
			break;
		}
	}
	free(tree);
	free(list);
	return ans;
}
void update(int idx)
{
	tree[idx] = 0;
	idx >>= 1;
	while (idx)
	{
		tree[idx] = tree[idx << 1] + tree[idx << 1 | 1];
		idx >>= 1;
	}
}
int qu(int node, int start, int end, int left, int right)
{
	int mid;
	if (left > end || right < start)
	{
		return 0;
	}
	if (left <= start && end <= right)
	{
		return tree[node];
	}
	mid = (start + end) >> 1;
	return qu(node << 1, start, mid, left, right) + qu(node << 1 | 1, mid + 1, end, left, right);
}
int kth(int node, int start, int end, int k)
{
	int mid;
	if (start == end)
	{
		return start;
	}
	mid = (start + end) >> 1;
	if (tree[node << 1] >= k)
	{
		return kth(node << 1, start, mid, k);
	}
	else
	{
		return kth(node << 1 | 1, mid + 1, end, k - tree[node << 1]);
	}
}