인프런 커뮤니티 질문&답변

코테님의 프로필 이미지
코테

작성한 질문수

10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트

8-D

8-D 북서풍

작성

·

224

0

- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요!
- 먼저 유사한 질문이 있었는지 검색해보세요.
- 서로 예의를 지키며 존중하는 문화를 만들어가요.
- 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.

안녕하세요. 강사님 ,

3시간 가량 이 문제를 붙잡아도 도저히 이해가 되지 않네요.. ㅜ - ㅜ

 

아래 코드에서 find_index 함수의 역할이 너무 어려워요.

왜 update(find~+1) 을 하는건지,

find_index 함수는 뭘 출력하는건지 모르겠어요.

v[i].second의 인덱스 출력은 아닌 것 같고,
v[i].second의 개수도 아닌 것 같고...

강의를 3번 듣고, 구글링도 많이 해봤는데..

혼자 계속 고민해봤자 답이 안나올 것 같아요.

 

<아래 코드 출력값>

-10 -10 10 10

-10 => 1

10 => 2

-10 => 1

10 => 2

 

 

ll ret = 0;
    cout << "\n"
         << v[0].second << "  => " << find_index(v[0].second) << "\n";
    update(find_index(v[0].second) + 1, 1);

    for (int i = 1; i < n; i++)
    {
      int idx = find_index(v[i].second) + 1;
      cout << "\n"
           << v[i].second << "  => " << find_index(v[i].second) << "\n";
      ret += 1LL * sum(idx);
      update(idx, 1);
    }

답변 1

0

큰돌님의 프로필 이미지
큰돌
지식공유자

안녕하세요 구재연님 ㅎㅎ

먼저 여기까지 오시느라 수고 많으셨습니다.

 

아래 코드에서 find_index 함수의 역할이 너무 어려워요.

왜 update(find~+1) 을 하는건지,

find_index 함수는 뭘 출력하는건지 모르겠어요.

>>

이코드 말씀이시죠?

        for(int i = 0; i < n; i++){
            cin >> x >> y;
            a.push_back({x, y * -1});
            _y.push_back(y * -1);
        }
        sort(a.begin(), a.end());
        sort(_y.begin(), _y.end());
        ll ret = 0;
        update(find_index(_y, a[0].second) + 1, 1);

_y는 y좌표들이 반대로 담깁니다.

_y = -1 * y좌표리스트

a[0].second가 의미하는 것은 y * -1가 들어간 값입니다.

해당 값을 찾아서 인덱스를 반환합니다.

int find_index(const vector<int> & _y, int value){
    int lo = 0, hi = _y.size() - 1;
    while(lo <= hi){
        int mid = (lo + hi) / 2;
        if(_y[mid] == value) return mid;
        if(_y[mid] < value) lo = mid + 1;
        else hi = mid - 1;
    }
}

이미 sort가 되어있기 때문에 이분탐색을 쓸 수가 있습니다.

예를 들어

-1, -2, -3, -4가 들어가있고 -3을 찾는다면 2라는 인덱스를 반환합니다.

자 좀 더 쉬운 예제로 들어볼게요.


1
3
5 1 
4 2
3 3

이거를 기반으로.

#include <bits/stdc++.h>
#define max_n 75004
typedef long long ll;
using namespace std;
int n, x, y, t;
vector<int> tree, _y;
vector<pair<int, int>> a;

int sum (int idx){
    int ret = 0;
    while(idx > 0){
        ret += tree[idx];
        idx -= (idx & -idx);
    }
    return ret;
}
void update(int pos, int value){
    int idx = pos;
    while(idx <= n){
        tree[idx] += value;
        idx += (idx & -idx);
    }
    return;
}
int find_index(const vector<int> & _y, int value){
    int lo = 0, hi = _y.size() - 1;
    while(lo <= hi){
        int mid = (lo + hi) / 2;
        if(_y[mid] == value) return mid;
        if(_y[mid] < value) lo = mid + 1;
        else hi = mid - 1;
    }
}
int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
    cout.tie(NULL);
    cin >>t;
    while(t--){
        cin >> n;
        a.clear(); _y.clear();
        tree.clear();
        tree.resize(n + 1);
        for(int i = 0; i < n; i++){
            cin >> x >> y;
            a.push_back({x, y * -1});
            _y.push_back(y * -1);
        }
        sort(a.begin(), a.end());
        sort(_y.begin(), _y.end());
        ll ret = 0; 
        update(find_index(_y, a[0].second) + 1, 1);
        for(int i = 1; i < n; i++){
            cout << "index\n";
            cout << a[i].second << " : " << find_index(_y, a[i].second) << "\n";
            int idx = find_index(_y, a[i].second) + 1;
            ret += 1LL * sum(idx);update(idx, 1);
        }
        cout << ret << "\n";
    }
	return 0;
}

디버깅 코드는 앞의 코드와 같습니다.

첫번째 인덱스를 제외하고 출력하는거라 이렇게 출력이 될 겁니다.

index

-2 : 1

index

-1 : 2

 

이 의미는.

-2를 _y 안에서 찾아줘.

가 되죠.

_y는 -3, -2, -1이 들어가있겠죠?

이 안에서 -2는 1을. -1는 2를 반환하게 됩니다.

 

 

그 이후 해당 인덱스 + 1에 해당 하는 펜윅트리를 업데이트합니다.

이 때 + 1을 하는 이유는 인덱스는 0 ~ n - 1이렇게 반환될텐데

펜윅트리는 1부터 시작하므로 + 1을 해줍니다.

업데이트를 왜하냐?

>>

펜윅트리를 통해 우리는 어떤 정점에서 그 이전에 몇개의 정점이 얼마나 있는지를 쉽게 파악할 수 있습니다.

예를 들어

1 1 1 1 3이라고 했을 때 3 뒤에는 1이 4개가 있죠?

이를 빨리 파악할 수 있게 하는 자료구조가 펜윅트리입니다.

1이라는 값에 +1을 함으로써 결국 1이라는 값은 4만큼의 크기를 가지고 3에서 그 밑에 있는 수를 끄집어낸다 했을 때

sum이라는 함수로 4개를 끄집어낼 수 있는 것이죠.

다시 예를 들면

1 1 1 1 2 2 3 이렇게 되어있을 떄

1 : 4, 2 : 2 이런식으로 되어서

sum()을 기반으로

3밑에 6개가 있네 를 쉽게 뽑아낼 수 있게 되는 것입니다.



또 질문 있으시면 언제든지 질문 부탁드립니다.

좋은 수강평과 별점 5점은 제게 큰 힘이 됩니다. :)

감사합니다.

강사 큰돌 올림.


코테님의 프로필 이미지
코테

작성한 질문수

질문하기