티스토리 뷰

[BOJ 1517] 버블 소트 - P5

문제 설명 :

n개의 수를 버블 소트할 때, swap이 총 몇 번 일어나는지 세야 한다.

문제 풀이 :

i번 째 수를 기준으로 자신의 왼쪽 ( [1, i-1] ) 에 있는 수들 중에서 자신보다 큰 값이 몇 개인지 세면 된다. n이 50만이기 때문에 log 시간만에 세야 한다. 두 가지 풀이가 가능하다.
첫 번째 풀이는 mergesort tree를 이용하면 된다. mergesort tree는 [l,r]구간 상에서 x보다 작은 수의 값을 log만에 구할 수 있다. 이는 얼마 전의 k번째 수 문제에서도 언급했었다.
두 번째 풀이는 바로 offline query를 이용하는 것이다. 이 문제는 쿼리별로 독립시행이다. 즉 이번 쿼리의 정답이 그 이후의 쿼리의 정답에 영향을 끼치지 않는다. 그렇기 때문에 원소 값들을 전처리하여 문제를 풀기에 유리하게끔 만든 뒤에 query를 받을 수 있다는 뜻이다.
이 문제에서 할 전처리는 원소들을 모두 받아서 좌표압축을 진행할 것이다. 좌표압축을 하고 나면 i번째 원소가 전체 원소 중에서 몇 번째 원소인지(오름차순 기준) map에다가 저장을 해 놓을 것이다.
그리고 나서 1번째 인덱스부터 차례로 자신의 왼쪽에 있는 수 중에서 자신보다 큰 값의 개수를 카운트할 것이다. 위에서 좌표압축의 결과를 map에다가 저장해놓았으므로 query는 getSum(1,map[arr[i]]) 같은 형태로 받아서 ans에다가 값을 더해나가면 된다. 그런 다음 update를 통해서 해당 인덱스 값을 1 증가시켜주면 된다.

배울 점 :

offline query와 좌표압축을 통해 i번째 값이 어느 위치(pos)에 들어가게 될 것인지 미리 배정할 수 있고, 이를 query(1,pos)같은 형태로 만들 수 있다.

소스코드 :

#include<stdio.h>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;

const int SIZE = 500009;
int tree[SIZE*8],arr[SIZE];
vector<int> v;
int startIdx=1;

int count(int node,int cl, int cr,int ql,int qr){
    if(cl > qr || ql > cr) return 0;
    if(qr >= cr && cl >= ql) {
        return tree[node];
    }

    int mid = (cl+cr)/2;
    return count(node*2,cl,mid,ql,qr) + count(node*2+1,mid+1,cr,ql,qr);
}

void update(int node){
    node = node + startIdx - 1;
    tree[node]++;
    int par = node / 2;
    while(par >= 1){
        tree[par] = tree[par*2] + tree[par*2+1];
        par /= 2;
    }
    return;
}

int main(){
    int n;    scanf("%d",&n);

    for(; startIdx < n ; startIdx *= 2);
    for(int i=1 ; i<=n ; i++){
        scanf("%d",&arr[i]);
        v.push_back(arr[i]);
    }

    sort(v.begin(), v.end());
    v.erase(unique(v.begin(),v.end()), v.end());

    map<int,int> compress;
    for(int i=0 ; i<v.size() ; i++){
        compress[v[i]] = i + 1;
    }

    ll ans = 0;
    for(int i=1 ; i<=n ; i++){
        ans += 1LL* count(1,1,startIdx,compress[arr[i]] + 1,startIdx);
        update(compress[arr[i]]);
    }
    printf("%lld\n",ans);
    return 0;
}

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

[BOJ 11658]구간 합 구하기3  (0) 2021.11.13
[BOJ 2243] 사탕 상자, [BOJ 9426] 중앙값 측정  (0) 2021.10.29
[CF 1042D] Petya and Array  (0) 2021.10.21
[BOJ 7469] K번째 수  (0) 2021.10.20
[BOJ 1725] 히스토그램  (0) 2021.10.15
댓글