※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 14413번 문제인 Poklon이다.
문제는 아래 링크를 확인하자.

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

 

14413번: Poklon

The output must consist of Q lines, each line containing the answer to a query, respectively.

www.acmicpc.net

주어지는 쿼리를 [L,R]로 표현할 때 쿼리들을 R 오름차순으로 정렬해 각 쿼리의 답을 구하고 원래의 쿼리 순서대로 답을 출력하는 offline query 테크닉을 이용하자.

 

또한, [L,R]의 구간합을 구하면 원 배열에서 구간 내 정확히 두 번 등장하는 수의 개수를 얻을 수 있는 segment tree를 하나 만들어 문제를 해결하자. 이는 수열의 각 수에 대하여 이 수가 앞서 등장한 가장 가까운 위치, 두번째로 가까운 위치, 세번째로 가까운 위치가 어디인지를 저장해 두는 것으로 구현이 가능하다. 자세한 로직은 아래의 코드를 참고하자.

 

위와 같은 풀이와 별개로, sqrt decomposition을 이용하는 것으로도 이 문제를 해결할 수 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;

int seg[1048677];

void upd(int L, int R, int qI, int qVal, int sI) {
	if (R < qI || qI < L) return;
	seg[sI] += qVal;
	if (L < R) {
		upd(L, (L + R) / 2, qI, qVal, sI * 2);
		upd((L + R) / 2 + 1, R, qI, qVal, sI * 2 + 1);
	}
}

int rangesum(int L, int R, int qL, int qR, int sI) {
	if (R < qL || qR < L) return 0;
	if (qL <= L && R <= qR) return seg[sI];
	return rangesum(L, (L + R) / 2, qL, qR, sI * 2) + rangesum((L + R) / 2 + 1, R, qL, qR, sI * 2 + 1);
}

struct query {
	int qidx, L, R, ans;
	query() {};
	query(int qidx, int L, int R) {
		this->qidx = qidx, this->L = L, this->R = R;
	}
};

bool compR(query& q1, query& q2) {
	return q1.R < q2.R;
}

bool compidx(query& q1, query& q2) {
	return q1.qidx < q2.qidx;
}

int N, Q;
int arr[500001];
map<int, int> mp;
int idx = 1;

query qry[500000];
int curidx = 1, curqry = 0;
int previdx[500001], prevprevidx[500001], prevprevprevidx[500001];

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> N >> Q;

	for (int i = 1; i <= N; i++) {
		int x; cin >> x;
		if (mp.find(x) == mp.end()) {
			arr[i] = idx;
			mp.insert(make_pair(x, idx));
			idx++;
		}
		else arr[i] = mp[x];
	}
	for (int i = 0; i < Q; i++) {
		int L, R; cin >> L >> R;
		qry[i] = query(i, L, R);
	}
	sort(qry, qry + Q, compR);

	while (curqry < Q) {
		int& L = qry[curqry].L, & R = qry[curqry].R;
		while (curidx <= R) {
			int num = arr[curidx];
			if (previdx[num] == 0) previdx[num] = curidx;
			else if (prevprevidx[num] == 0) {
				upd(1, N, previdx[num], 1, 1);
				prevprevidx[num] = previdx[num];
				previdx[num] = curidx;
			}
			else if (prevprevprevidx[num] == 0) {
				upd(1, N, prevprevidx[num], -2, 1);
				upd(1, N, previdx[num], 1, 1);
				prevprevprevidx[num] = prevprevidx[num];
				prevprevidx[num] = previdx[num];
				previdx[num] = curidx;
			}
			else {
				upd(1, N, prevprevprevidx[num], 1, 1);
				upd(1, N, prevprevidx[num], -2, 1);
				upd(1, N, previdx[num], 1, 1);
				prevprevprevidx[num] = prevprevidx[num];
				prevprevidx[num] = previdx[num];
				previdx[num] = curidx;
			}
			curidx++;
		}

		qry[curqry].ans = rangesum(1, N, L, R, 1);
		curqry++;
	}

	sort(qry, qry + Q, compidx);
	for (int i = 0; i < Q; i++) cout << qry[i].ans << '\n';
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 1222 // C++] 홍준 프로그래밍  (0) 2022.10.09
[BOJ 14410 // C++] Pareto  (0) 2022.10.08
[BOJ 25050 // C++] 최고의 간선  (0) 2022.10.06
[BOJ 25049 // C++] 뮤직 플레이리스트  (0) 2022.10.05
[BOJ 25048 // C++] 랜선 연결  (1) 2022.10.04

+ Recent posts