https://www.acmicpc.net/problem/3653
&Title
3653번 - 영화 수집
&Question
상근이는 영화 DVD 수집가이다. 상근이는 그의 DVD 콜렉션을
쌓아 보관한다.보고 싶은 영화가 있을 때는, DVD의 위치를 찾은
다음 쌓아놓은 콜렉션이 무너지지 않게 조심스럽게 DVD를 뺀다. 영화를
다 본 이후에는 가장 위에 놓는다.상근이는 DVD가 매우 많기
때문에, 영화의 위치를 찾는데 시간이 너무 오래 걸린다. 각
DVD의 위치는, 찾으려는 DVD의 위에 있는 영화의 개수만 알면
쉽게 구할 수 있다. 각 영화는 DVD 표지에 붙어있는
숫자로 쉽게 구별할 수 있다.각 영화의 위치를 기록하는 프로그램을
작성하시오. 상근이가 영화를 한 편 볼 때마다 그 DVD의
위에 몇 개의 DVD가 있었는지를 구해야 한다.
&Input
첫째 줄에 테스트 케이스의 개수가 주어진다. 테스트 케이스의
개수는 100개를 넘지 않는다.각 테스트 케이스의 첫째 줄에는 상근이가
가지고 있는 영화의 수 n과 보려고 하는 영화의 수
m이 주어진다. (1 ≤ n, m ≤ 100,000) 둘째
줄에는 보려고 하는 영화의 번호가 순서대로 주어진다.영화의 번호는 1부터
n까지 이며, 가장 처음에 영화가 쌓여진 순서는 1부터 증가하는
순서이다. 가장 위에 있는 영화의 번호는 1이다.
&Output
각 테스트 케이스에 대해서 한 줄에 m개의 정수를
출력해야 한다. i번째 출력하는 수는 i번째로 영화를 볼 때
그 영화의 위에 있었던 DVD의 개수이다. 상근이는 매번 영화를
볼 때마다 본 영화 DVD를 가장 위에 놓는다.
&Example
-input
2
3 3
3 1 1
5 3
4 4 5
-output
2 1 0
3 0 4
요약
dvd를 일자로 쌓아둔다.
i번째 dvd를 뽑아서 보고 가장 위에 둔다.
빼기전 i번째 dvd 위에 있는 dvd개수를 매번 출력하라.
접근
아이디어 자체가 떠올리기가 정말 힘들다. 세그의 크기를 n+m으로 잡아줘서 쌓아 올릴 자리를 미리 만들어준다.
구간합을 통해 위에 있는 dvd수를 구하고, update를 통해 기존 위치를 0으로 갱신, 위를 1로 갱신해준다.
풀이
평번한 합세그를 이용한다.
미리 node에 해당 번호의 카드들의 위치의 기록해둔다.
// m+1 ~ n+m의 값 1로 업데이트
for (int i = m + 1; i <= n + m; ++i) {
update(1, i, 1, 1, n + m);
node[i - m] = i;
}
m~1까지가 이제 뽑은 카드들을 쌓을 자리다. 따라서 1~node[k]-1을 쿼리해주면 해당 위치의 카드 위에 카드의 개수를 얻을 수 있다. 이제 해당 위치를 0으로 업데이트해주고, node[k]값을 맨위 값인 count로 갱신해주고 해당 위치를 1로 업데이트해준다.
int k, count = m; // count는 쌓을 위치
for (int i = 0; i < m; ++i) {
cin >> k;
// 1(맨위)~해당카드 위치바로 위까지 개수 쿼리합
cout << query(1, 1, node[k] - 1, 1, n + m) << ' ';
// 현재 위치 카드 빼주고(0), 맨위에 카드 쌓아줌(1)
update(1, node[k], 0, 1, n + m);
node[k] = count--;
update(1, node[k], 1, 1, n + m);
}
댓글남기기