레야몬
[C++] 13547번 수열과 쿼리 5 - 오프라인 쿼리, mo's 본문
1. 문제
- 길이가 N인 수열 Ai이 주어진다. 다음 쿼리를 수행하는 프로그램을 작성하시오.
- i j: Ai, Ai+1, ..., Aj에 존재하는 서로 다른 수의 개수를 출력하라.
<입력>
- -1- 수열의 크기 \(N(1 \leq N \leq 100,000)\)
- -2- A1, A2, ..., AN \((1 \leq A_{i} \leq 1,000,000))\)
- -3- 쿼리의 개수 M \((1 \leq M \leq 100,000)\)
- -M개- 쿼리 i, j \((1 \leq i \leq j \leq N)\)
<출력>
- 한 줄에 하나씩 각각의 쿼리의 정답을 출력하라.
2. 재정의
- X
3. 해결 방법
- 쿼리 정렬로 i/sqrt(N)에 따라 정렬하고 만약 같다면 j가 큰 걸로 오름차순 정렬하기
- isIn[A[i]]에 넣고 없으면 cnt++. 있으면 그대로
- 제거하면 isIn[A[i]]--, 제거해서 0이면 cnt-- 아니면 그대로
- 추가하면 isIn[A[i]]++, 추가하기 전에 0이면 cnt++ 아니면 그대로
4. 실수한 점, 개선할 점
- 개산할 때 계산량 줄이면 소요 시간 확 줄어듦.
<코드>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
const int MAX_N = 100001;
const int MAX_V = 1000001;
// Sqrt Decomposition
int sqrtN;
struct Query {
// 쿼리가 저장된 index와 시작점과, 끝점
int idx, s, e, sq;
// sort compare
bool operator < (Query &x) {
if(sq != x.sq)
return sq < x.sq;
return e < x.e;
}
};
// 수열의 크기 N, 쿼리의 개수 M
int N, M;
// 수열 A[i]
int A[MAX_N];
// 쿼리 배열
vector<Query> query;
// 이미 부분 수열에 포함되어 있는가?
int isIn[MAX_V];
// 서로 다른 수의 개수
int cnt;
// 쿼리 결과
int ans[MAX_N];
void input() {
cin >> N;
sqrtN = (int)sqrt(N);
for(int i=1; i<=N; i++)
cin >> A[i];
cin >> M;
for(int i=0; i<M; i++) {
//query
int a, b;
cin >> a >> b;
query.push_back({i, a, b, (a-1)/sqrtN});
}
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
input();
// mo's algorithm
sort(query.begin(), query.end());
// 처음은 일일이 구해주기
int s = query[0].s, e = query[0].e;
for(int i=s; i<=e; i++) {
if(!isIn[A[i]])
cnt++;
isIn[A[i]]++;
//cout << A[i] << ' ';
}
ans[query[0].idx] = cnt;
for(int i=1; i<M; i++) {
while(s < query[i].s)
if(!(--isIn[A[s++]]))
cnt--;
while(s > query[i].s)
if(!(isIn[A[--s]]++))
cnt++;
while(e < query[i].e)
if(!(isIn[A[++e]]++))
cnt++;
while(e > query[i].e)
if(!(--isIn[A[e--]]))
cnt--;
ans[query[i].idx] = cnt;
}
for(int i=0; i<M; i++)
cout << ans[i] << '\n';
return 0;
}
<Sqrt Decomposition>
https://justicehui.github.io/medium-algorithm/2019/03/03/SqrtDecomposition/
[구간쿼리] Sqrt Decomposition
개요 이번 글에서는 특정 구간에 대한 쿼리를 O(√N)에 처리할 수 있는 SQRT Decomposition에 대해 알아보도록 하겠습니다. 사실 Segment Tree를 사용하면 유사한 기능을 O(log N)이라는 훌륭한 시간에 수행
justicehui.github.io
<Mo's Algorithm>
https://justicehui.github.io/hard-algorithm/2019/06/17/MoAlgorithm/
[구간쿼리] Mo's Algorithm(모스 알고리즘)
서론 약 3개월 전에 이 글을 쓰면서 잠시 Mo’s Algorithm을 언급했었습니다. 이 글에서 모스 알고리즘의 설명을 다루면서 모스 알고리즘을 이용해서 푸는 몇 가지 문제를 풀어보고자 합니다.
justicehui.github.io
※현재 고등학교 등교 중인 학생입니다. 이제 알고리즘을 본격적으로 공부하기 시작해서 아직 초보입니다. 혹시 제가 잘못 알고 있는 점이나 더 좋은 풀이 방법이 있어 댓글에 남겨주시면 감사히 하나하나 열심히 읽어보겠습니다. 좋아요, 단순한 댓글 한마디라도 저에겐 큰 힘이 됩니다! 감사합니다.
'알고리즘 > 백준' 카테고리의 다른 글
[C++] 16978번 수열과 쿼리 22 - 자료 구조, 세그먼트 트리, 오프라인 쿼리 (0) | 2022.11.18 |
---|---|
[C++] 13548번 수열과 쿼리 6 - 오프라인 쿼리, mo's (0) | 2022.11.13 |
[C++] 13544번 수열과 쿼리 3 - 자료 구조, 정렬, 세그먼트 트리, 머지 소트 트리 (0) | 2022.11.09 |
[C++] 13537번 수열과 쿼리 1 - 자료 구조, 정렬, 세그먼트 트리, 머지 소트 트리 (0) | 2022.11.09 |
[C++] 11408번 열혈강호 5 - 최대 유량, 최소 비용 최대 유량 (0) | 2022.11.09 |
Comments