반응형

문제 출처 :


https://www.acmicpc.net/problem/2517



알고리즘 분석 :


문제 해결에 필요한 사항

1. 세그먼트 트리 :: http://www.crocus.co.kr/648


이 문제의 핵심은 다음과 같다.


1. 값이 10억까지 들어올 수 있지만 n제한이 50만 이하이다. 따라서 좌표 압축이 가능하다.


2. 좌표압축이 이루어 진다면 세그먼트 트리를 이용하여 문제를 해결 할 수 있다.


3. 세그먼트 트리를 이용하는 법은 다음과 같다.


현재 입력값보다 먼저 들어온 값들 중 자신보다 큰 값이 있으면 


그 개수를 count 해주고, 없다면 0 + 1(자신)을 해준다는 원리로 진행한다.




이 문제를 풀때 필자는 다음과 같은 생각을 몇가지 해보았다.



현재 들어온 값이 맵의 end() -1에 존재하면 끝에 위치하는거니 1등이 될 가능성이 있는 것이고, 그게 아닌 모든 값들은 맵에서 몇번째에 위치하는지 order를 구해주면 된다고 생각했다.



그런데 order 구하는 방법이 logN에 끝날 줄 알았는데 그 방법을 찾지 못하였다.


예를들어 vector에서는 lower_bound() - V.begin()을 하면 인덱스가 나타나지만 map은 균형 이진 트리라 인덱스 개념이 없다보니 안되는 것 같았다.


틀린 코드는 다음과 같다.


이때 아래 distance 자체가 O(n)에 끝나는 방식이고, lower_bound 자체는 map에서 제공하지만, 인덱스를 반환해줄 방법이 없다.


시간초과(TLE) 코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <cstdio>
#include <map>
 
using namespace std;
 
map<intint> mp;
 
int main()
{
    int n;
    scanf("%d"&n);
 
    for (int i = 1; i <= n; i++)
    {
        int val;
        scanf("%d"&val);
        mp[val] = i;
 
        auto pos = mp.lower_bound(val);
        if (pos == --mp.end())
            printf("1\n");
 
        else
            printf("%d\n", i - distance(mp.begin(), pos));
    }
    return 0;
}
 
//                                                       This source code Copyright belongs to Crocus
//                                                        If you want to see more? click here >>
Crocus














소스 코드 : 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
 
using namespace std;
 
typedef pair<intint> pii;
 
bool comp(const pii &a, const pii &b)
{
    return a.second < b.second;
}
 
void update(vector<int> &tree, int node, int start, int end, int idx)
{
    if (!(start <= idx && idx <= end))
        return ;
 
    tree[node] += 1;
 
    if (start != end)
    {
        int mid = (start + end) / 2;
        update(tree, node * 2, start, mid, idx);
        update(tree, node * + 1, mid + 1, end, idx);
    }
 
}
int query(vector<int> &tree, int node, int start, int end, int left, int right)
{
    if (start > right || end < left)
        return 0;
    
    if (left <= start && end <= right)
        return tree[node];
 
    int mid = (start + end) / 2;
 
    return query(tree, node * 2, start, mid, left, right) + query(tree, node * + 1, mid + 1, end, left, right);
}
 
int main()
{
    int n;
    scanf("%d"&n);
 
    int h = (int)ceil(log2(500000));
    int tree_size = << (+ h);
 
    vector<pii> arr;
    vector<int> tree(tree_size);
 
    for (int i = 0; i < n; i++)
    {
        int val;
        scanf("%d"&val);
        arr.push_back({ val, i });
    }
 
    sort(arr.begin(), arr.end());
 
    // 좌표 압축
    for (int i = 0; i < n; i++)
        arr[i].first = i;
 
    sort(arr.begin(), arr.end(), comp);
 
    for (int i = 0; i < n; i++)
    {
        int ans = i - query(tree, 105000000, arr[i].first) + 1;
        printf("%d\n", ans);
 
        update(tree, 10500000, arr[i].first);
    }
    return 0;
}
 
//                                                       This source code Copyright belongs to Crocus
//                                                        If you want to see more? click here >>
Crocus


반응형

'Applied > 알고리즘 문제풀이' 카테고리의 다른 글

[1535번] 안녕  (0) 2017.08.24
[2585번] 경비행기  (8) 2017.08.24
[2638번] 치즈  (0) 2017.08.24
[1280번] 나무 심기  (0) 2017.08.17
[4796번] 캠핑  (0) 2017.08.17