티스토리 뷰

[BOJ 2912]백설공주와 난쟁이 - P3

문제 설명

난쟁이가 n명 주어진다. 난쟁이는 각자 하나의 숫자를 갖고 있다. 이어서 쿼리가 주어진다. 각 쿼리는 [l,r]형태로 주어지는데, [l,r] 구간 안에서 난쟁이가 갖고 있는 특정 숫자의 개수가 구간의 길이(r-l+1)의 절반을 초과하는지 묻고 있다.

문제 풀이

특정 숫자의 개수가 구간 길이의 절반을 초과한다면, '반드시' 구간의 절반 경계를 지날 때, 등장하는 수가 같아야만 한다. 단, 역은 성립하지 않는다. 즉 절반의 경계에서 등장하는 수가 같더라도 그 수의 개수가 절반을 초과하지 않을 수도 있다. 따라서 그냥 정답의 '후보'만 된다는 것이고 이는 나중에 실제로 정답인지 검증하는 과정을 거쳐야 한다. 이러한 '후보'는 최대 logL 개가 나온다.(L = r-l+1)
따라서 모든 후보를 구해놓고 각 후보마다 실제로 개수가 절반이 넘는지 검증해보면 된다. 검증할 때는 전처리로 각 숫자가 등장하는 인덱스를 벡터에 넣어놓고 [l,r]구간에 몇개가 등장하는지 이분 탐색을 돌려보면 된다.

소스 코드

#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;

const int SIZE = 300009;
vector<int> tree[SIZE*8],color[10009];
int startIdx=1;

void makeMergeSortTree(){
    for(int i = startIdx - 1; i>=1 ; i--){
        int lChild = i*2,rChild = i*2+1;
        int lIdx = 0,rIdx = 0;
        int sz = tree[lChild].size();

        while(lIdx < tree[lChild].size() && rIdx < tree[rChild].size()){
            if(tree[lChild][lIdx] > tree[rChild][rIdx]) tree[i].push_back(tree[rChild][rIdx++]);
            else tree[i].push_back(tree[lChild][lIdx++]);
        }

        if(lIdx < tree[lChild].size()){
            for(int j = lIdx ; j < tree[lChild].size() ; j++){
                tree[i].push_back(tree[lChild][j]);
            }
        }
        else for(int j = rIdx ; j < tree[rChild].size() ; j++){
            tree[i].push_back(tree[rChild][j]);
        }
    }

}

vector<int> query(int node,int cl, int cr,int ql,int qr){
    vector<int> res;
    if(tree[node].size()==0) return res;
    int mid = (cl+cr)/2;
    int sz = cr - cl +1;
    if(node >= startIdx) {
        res.push_back(tree[node][0]);
        return res;
    }
    if(cl > qr || ql > cr) return res;
    if(qr >= cr && cl >= ql) {
        if(tree[node][sz/2-1] == tree[node][sz/2]) {
            res.push_back(tree[node][sz/2]);
        }
        return res;
    }

    res = query(node*2,cl,mid,ql,qr);
    vector<int> R = query(node*2+1,mid+1,cr,ql,qr);
    for(int i : R)
        res.push_back(i);

    return res;
}

int countColor(int l,int r,int i){
    int res = upper_bound(color[i].begin(),color[i].end(),r) - 
        upper_bound(color[i].begin(),color[i].end(),l-1);

    return res;
}

int main(){
    int n,c;    scanf("%d %d",&n,&c);
    for(;startIdx < n ; startIdx *= 2);

    for(int i=1 ; i<=n ; i++){
        int inp;    scanf("%d",&inp);
        tree[startIdx + i - 1].push_back(inp);
        color[inp].push_back(i);
    }

    makeMergeSortTree();

    int q;  scanf("%d",&q);
    while(q--){
        int l,r;    scanf("%d %d",&l,&r);
        vector<int> candid = query(1,1,startIdx,l,r);

        int check = 0;
        for(int i : candid){
            if(countColor(l,r,i) > (r-l+1)/2){
                printf("yes %d",i);
                check = 1;
                break;
            }
        }

        if(!check) printf("no");
        printf("\n");
    }
    return 0;
}

'Problem Solving > Segment Tree' 카테고리의 다른 글

[BOJ 15899]트리와 색깔  (0) 2021.11.16
[BOJ 2820] 자동차 공장  (0) 2021.11.16
[BOJ 11658]구간 합 구하기3  (0) 2021.11.13
[BOJ 2243] 사탕 상자, [BOJ 9426] 중앙값 측정  (0) 2021.10.29
[BOJ 1517] 버블 소트  (0) 2021.10.21
댓글