본문 바로가기

알고리즘/세크먼트트리

2465 줄세우기

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

문제


N명의 사람들이 어떤 공연장에 입장하기 위해서 한 줄로 서 있다. 
줄 서 있는 각 사람은 자기 앞에 서 있는 사람들 중에서 자기보다 키가 작거나 같은 사람들의 수를 알고 있다. 
그러면, 이 수들을 표시하는 수열을 S라고 한다.
N명의 키 집합과 수열 S가 주어질 때, 원래 줄 서 있는 키 순서를 정확히 찾아내는 프로그램을 작성하시오. 
예를 들어서, 사람들의 키 집합이 다음과 같이 주어진다 (여기서, 같은 키의 사람들이 여러 명 존재할 수 있어서 중복이 포함된다). 
{120, 167, 163, 172, 145, 134, 182, 155, 167, 120, 119, 156}
또한 각 사람이 자기 앞에 있는 사람들 중에서 자기보다 키가 작거나 같은 사람들의 수를 표시하는 수열 S는 다음과 같이 주어진다. 
S :   0 1 0 0 3 2 6 7 4 6 9 4
그러면, 실제 줄 서 있는 사람들의 키 순서는 다음과 같다. 
134 167 120 119 156 120 167 182 155 163  172 145

입력

첫째 줄에는 전체 사람의 수 N (1<=N<=100,000)이 주어진다. 다음 N개의 줄에 사람들의 키를 나타내는 양의 정수가 하나씩 주어진다. 
여기서 모든 키들은 2*10^9이하이다. 그리고 마지막 줄에 수열 S가 한 줄로 주어진다. 단 그 수열의 수는 하나의 공백을 두고 나타난다.

출력

출력은 N개의 줄로 구성된다. N개의 줄 각각에 원래 줄 서 있는 사람들의 키를 순서대로 하나씩 출력한다.

예제 입력1

12
120
167
163
172
145
134
182
155
167
120
119
156
0 1 0 0 3 2 6 7 4 6 9 4

예제 출력1

134
167
120
119
156
120
167
182
155
163
172
145

  • 노드 접근시 노드의 합에서 -1 해준다.
  • 왼쪽 노드 접근 조건 : Position ≤ 왼쪽 노드의 합
  • 오른쪽 노드 접근 조건 : Position > 왼쪽 노드의 합 → Postion = Position - 왼쪽 노드의 합

  • 풀이 소스
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main_2465 {
    static void init(int[] tree, int[] arr, int node, int start, int end) {
        if (start == end) {
            tree[node] = 1;
            return;
        }
        int mid = (start + end) / 2;
        int leftNodeIdx = node * 2;
        int rightNodeIdx = node * 2 + 1;
        init(tree, arr, leftNodeIdx, start, mid);
        init(tree, arr, rightNodeIdx, mid + 1, end);
        tree[node] = tree[leftNodeIdx] + tree[rightNodeIdx];
    }

    static void update(int[] tree, int[] visit, int[] tall, int node, int start
                                                , int end, int index, int position) {
        tree[node]--;
        if (start == end) {
            visit[index] = tall[start];
            return;
        }
        int mid = (start + end) / 2;
        int leftNodeIdx = node * 2;
        int rightNodeIdx = node * 2 + 1;
        if (position <= tree[leftNodeIdx]) {
            update(tree, visit, tall, leftNodeIdx, start, mid, index, position);
            return;
        }
        if (position > tree[leftNodeIdx]) {
            update(tree, visit, tall, rightNodeIdx, mid + 1, end, index, position - tree[leftNodeIdx]);
            return;
        }
    }

    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
             BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out))) {
            int N = Integer.parseInt(br.readLine());

            int tall[] = new int[N + 1];
            int position[] = new int[N + 1];
            int visit[] = new int[N + 1];
            StringTokenizer st;
            int h = (int) Math.ceil(Math.log(N) / Math.log(2));
            int treeSize = (1 << (h + 1)) + 1;
            int tree[] = new int[treeSize];

            for (int i = 1; i <= N; i++) {
                st = new StringTokenizer(br.readLine());
                tall[i] = Integer.parseInt(st.nextToken());
            }
            st = new StringTokenizer(br.readLine());
            for (int i = 1; i <= N; i++) {
                position[i] = Integer.parseInt(st.nextToken());
            }
            tall = Arrays.stream(tall).sorted().toArray();
            init(tree, tall, 1, 1, N);
            for (int i = N; i >= 1; i--) {
                update(tree, visit, tall, 1, 1, N, i, position[i] + 1);
            }

            for (int i = 1; i <= N; i++) {
                bw.write(visit[i] + "\n");
            }
            bw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

'알고리즘 > 세크먼트트리' 카테고리의 다른 글

2042 구간 합 구하기  (0) 2021.06.10
7578 공장  (0) 2021.06.10
2517 달리기  (0) 2021.06.10
세그먼트트리  (0) 2021.06.10