[BOJ/2912] 백설공주와 난쟁이, c++

2021. 2. 19. 03:07·DEV/PS

www.acmicpc.net/problem/2912

 

2912번: 백설공주와 난쟁이

첫째 줄에 난쟁이의 수 N과 모자 색상의 수 C가 주어진다. (3 ≤ N ≤ 300,000, 1 ≤ C ≤ 10,000) 둘째 줄에는 각 난쟁이가 쓰고 있는 모자의 색상이 줄을 서 있는 순서대로 주어진다. 셋째 줄에는 사진

www.acmicpc.net

한줄 후기 : 세그 트리라도 푼게 어디야..

 

원래 확률적 알고리즘 파트라서 Mo's Algorithm 을 이용해 풀어봐야 하는 것 같다.

하지만.. 도저히 못풀겠음 구글링 좀 해서 봤는데 계속 시간 초과 나서 못 풀었다.

그래서 이 문제를 또 풀 수 있는 방법인 세그먼트 트리를 이용해 풀었다.

세그먼트 트리로 푸는 법은 간단하다. 

그냥 처음 트리를 생성할 때, 트리에는 해당 구간 내에 난쟁이들이 가장 많이 쓰고 있는 ( = 절반 넘게) 모자의 색상을 넣어주고, 만약 모든 색상이 절반을 넘지 못한다면, 그냥 -1을 넣는다.

그 후 구간 쿼리 a,b가 들어올 때 마다 세그먼트 트리를 돌면서 a~b 사이의 모자를 확인해 준다.  

 

 모자의 개수 cnt를 구하는 방법이 신기한데, 이 방법은 사실 내가 생각한건 아니고, 다른 분 설명을 참고해서 풀었다.

이진 탐색 upper_bound, lower_bound 를 이용한다.

모자 배열을 받을 때, 다른 vector idx에 해당 모자를 쓴 난쟁이들의 index를 함께 저장해둔다.

그리고 각 모자 색상 별 난쟁이 index를 정렬해준다.

 

이렇게 정렬하고 나서 특정 구간이 주어지고, idx 벡터에서 해당 구간(index)을 검색하면 나오는 upper(right) - lower(left) + 1 이 해당 구간 내에 그 모자를 쓴 난쟁이의 수가 됨을 알 수 있다. 

 

//AC
//BOJ 2912 백설공주와 난쟁이
#include <iostream>
#include <vector>
#include <algorithm>
#define SIZE 301010
using namespace std;
vector<int> idx[SIZE];
int arr[SIZE],  tree[SIZE*4];
int N, C;
void make(int node, int left, int right){
	if(left == right){
		tree[node] = arr[left];
		return;
	}
	int mid = (left+right) / 2;
	make(node*2, left, mid);
	make(node*2+1, mid+1, right);
	int lc = tree[node*2];
	int cnt = upper_bound(idx[lc].begin(), idx[lc].end(), right)-lower_bound(idx[lc].begin(), idx[lc].end(), left)+1; 
	if(cnt > (right-left+1)/2) {
		tree[node] = lc;
		return;
	}
	lc = tree[node*2+1];
	cnt = upper_bound(idx[lc].begin(), idx[lc].end(), right)-lower_bound(idx[lc].begin(), idx[lc].end(), left)+1; 
	if(cnt > (right-left+1)/2){
		tree[node] = lc;
		return;
	} 
	tree[node] = -1;
}
int segTree(int node, int left, int right, int start, int end){
	if(right<start || end < left)	return 0;
	if(start >= left && right >= end){
		int cnt = upper_bound(idx[tree[node]].begin(), idx[tree[node]].end(), right)-lower_bound(idx[tree[node]].begin(), idx[tree[node]].end(), left); 
		if(cnt > (right-left+1)/2){
			return tree[node];
		}
		else	return 0;
	}
	int mid = (start + end) / 2;
	int one = segTree(node*2 , left, right, start, mid);
	if(one > 0)	return one;
	int two = segTree(node*2+1, left, right, mid+1, end);
	if(two > 0)	return two;
	return 0;
}
int main(){
	int M, a, b;
	scanf("%d %d" , &N, &C);
	for(int i=0; i<N; i++){
		scanf("%d", &arr[i]);
		idx[arr[i]].push_back(i);
	}
	for(int i=1; i<=C; i++){
		sort(idx[i].begin(), idx[i].end());
	}		
	make(1, 0, N-1);
	scanf("%d", &M);
	while(M--){
		scanf("%d %d", &a, &b);
		int ans = segTree(1, a-1, b-1, 0, N-1);
		if(ans > 0)	printf("yes %d\n", ans);
		else	printf("no\n");
	}
	return 0;
}

 

 

 

 

저작자표시 비영리 변경금지 (새창열림)

'DEV > PS' 카테고리의 다른 글

[BOJ/20956] 아이스크림 도둑 지호, c++  (0) 2021.03.08
2021 SUAPC winter 주저리..  (0) 2021.03.04
[BOJ/11004] K번째 수 (QuickSelect로 풀기), c++  (0) 2021.02.18
[BOJ/8201] Pilots, c++  (0) 2021.02.15
PS용 비트 연산자(bit masking) 정리  (0) 2021.02.14
'DEV/PS' 카테고리의 다른 글
  • [BOJ/20956] 아이스크림 도둑 지호, c++
  • 2021 SUAPC winter 주저리..
  • [BOJ/11004] K번째 수 (QuickSelect로 풀기), c++
  • [BOJ/8201] Pilots, c++
jobchae
jobchae
말하는 감자지만, 코드를 끄적이는 Node.js 백엔드 개발자입니다.
  • jobchae
    JOBCHAE
    jobchae
  • 전체
    오늘
    어제
    • 🚀 JOBCHAE (182)
      • DEV (151)
        • PS (108)
        • Node.js (12)
        • React (3)
        • docker (1)
        • 잡다한 개발 일지 (21)
        • injection (1)
        • JS, TS (3)
        • DB (2)
      • 축구 (0)
      • 일상 (19)
      • 영화 (3)
      • 음악 (8)
  • 블로그 메뉴

    • 💻 Github
    • 🙋🏻 Linkedin
    • 📖 방명록
  • 링크

    • PS Github
  • 공지사항

  • 인기 글

  • 태그

    mongoDB
    PS
    솝트
    typescript
    nodejs
    JavaScript
    node.js
    react
    회고
    Express
    BFS
    알고리즘
    백준
    우선순위큐
    db
    일상
    슬랙
    리액트
    GitHub
    렛츠락페스티벌
    SOPT
    슬랙봇
    DFS
    앱잼
    위상정렬
    이분탐색
    Nest.js
    DP
    개발
    boj
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
jobchae
[BOJ/2912] 백설공주와 난쟁이, c++
상단으로

티스토리툴바