본문 바로가기

Dot Algo∙ DS/PS

[BOJ] 백준 5419번 북서풍 (Java)

    #5419 북서풍

    난이도 : 플레 4

    유형 : 세그먼트 트리 / 좌표 압축

     

    5419번: 북서풍

    각 테스트 케이스에 대해서, 북서풍을 타고 항해할 수 있는 섬의 쌍의 수를 출력한다.

    www.acmicpc.net

    ▸ 문제

    강한 북서풍이 불고 있다. 이 뜻은 동쪽과 남쪽 사이의 모든 방향으로 항해할 수 있다는 뜻이다. 북쪽이나 서쪽으로 항해하는 것은 불가능하다.

    작은 섬이 여러 개 있는 바다가 있다. 섬은 좌표 평면의 한 점으로 나타낼 수 있다. y 좌표가 증가하는 방향은 북쪽, x좌표가 증가하는 방향은 동쪽이다. 북서풍을 타고 항해할 수 있는 섬의 쌍의 수를 구하는 프로그램을 작성하시오.

     입력

    첫째 줄에 테스트 케이스의 개수가 주어진다.

    각 테스트 케이스의 첫째 줄에는 섬의 수 n (1 ≤ n ≤ 75000)이 주어진다. 다음 n개 줄에는 각 섬의 좌표 xi, yi가 주어진다. 두 섬의 좌표가 같은 경우는 없다. (-109 ≤ xi, yi ≤ 109)

     출력

    각 테스트 케이스에 대해서, 북서풍을 타고 항해할 수 있는 섬의 쌍의 수를 출력한다.

     

    문제 풀이  

    문제는 일단 세그먼트 트리이다. 좌표를 압축하여 자신보다 앞(북서쪽)에 위치한 섬들을 카운트해주면 된다. x, y를 완전탐색하면 O(n^2)이기 떄문에 트리 구조를 사용하여 로그함수대로 시간을 줄여주는 것이다.

     

    먼저 좌표를 그려보면서 북서풍을 타고 항해할 수 있는 섬이 어떻게 되는지 살펴보자.

    북서풍으로 탐색

     

    다음과 같이 북서풍으로 탐색한다는 것은 y축이 더 크거나 x축이 작은 곳을 탐색한다는 것과 같다는 것을 알 수 있다. 그러므로 이제 섬들을 1차원 좌표로 압축시켜 우선순위대로 자신의 앞(북서풍)에 몇 개의 섬이 위치했는지 카운트해주는 문제로 바꿔주면 된다.

     

    y좌표 압축하기

    1차원으로 압축시켜야 하기 때문에 그 기준이 x나 y좌표 어떤 것이 되어도 상관없다. 1번의 예제로 y축을 압축시킨다고 했을 때 시뮬레이션을 돌려보면 (-10, -10), (-10, 10), (10, -10), (10, 10)이라는 세 개의 섬이 있을 때 (-10, 2), (-10, 1), (10, 2), (10, 1)로 변한다. 

    • 어떻게 좌표를 압축시켜도 상관없다. 오름차순 내림차순. 트리에 어떻게 저장하고 어떻게 쿼리를 꺼낼지 그에따라 맞춰주기만 하면 된다. 나는 y축이 클수록 작은 인덱스를 부여했다. y=10은 1로, -10은 2로 압축했다.

     

    x좌표 오름차순 정렬

    그런 다음 x축을 오름차순으로 정렬해준다. 왜냐하면 서쪽에 있을수록(x값이 작을수록) 우선순위가 더 높기 때문이다. 그러면 세그먼트 트리에 (-10,1) → (-10,2) → (10,1) → (10,2)로 저장해준다.

     

    세그먼트 트리에 값 저장 및 카운팅

    1. (-10, 1)의 좌표 삽입

    • 원래 좌표는 (-10, 10)이다. 가장 앞의 인덱스에 저장된다. 
    • 자신보다 앞에 있는 좌표는 없으므로 0이 카운팅된다.

    (-10, 1)의 좌표 삽입

     

    1. (-10, 2)의 좌표 삽입

    • 원래 좌표는 (-10, -10)이다. 두 번째 인덱스에 저장된다.
    • 자신보다 앞에 있는 좌표는 1개 있으므로 1이 카운팅 된다

    (-10, 2)의 좌표 삽입

     

    1. (10, 1)의 좌표 삽입

    • 원래 좌표는 (10, 10)이다. 첫 번째 인덱스에 저장된다.
    • 좌표를 삽입하기 전 자신보다 앞에 있는 좌표는 1개(-10,1) 있으므로 1이 카운팅 된다. 이것이 x좌표를 오름차순한 이유이다.

     (10, 1)의 좌표 삽입

     

    1. (10, 2)의 좌표 삽입

    • 원래 좌표는 (10, -10)이다. 두 번째 인덱스에 저장된다.
    • 좌표를 삽입하기 전 자신보다 앞에 있는 좌표는 3개 전부이므로 3이 카운팅된다.

     (10, 2)의 좌표 삽입

     

    풀이 코드 

    import java.io.*;
    import java.util.*;
    
    public class Main {
    
    	static class Point{
    		int x, y;
    
    		public Point(int x, int y) {
    			this.x = x;
    			this.y = y;
    		}
    	}
    	
    	static int[] tree;
    	public static void main(String[] args) throws IOException{
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		int t = Integer.parseInt(br.readLine());
    		StringTokenizer st;
    		while(t-->0){
    			int n = Integer.parseInt(br.readLine());
    			
    			List<Point> p = new ArrayList<>();
    			for(int i=0; i<n; i++) {
    				st = new StringTokenizer(br.readLine());
    				p.add(new Point(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken())));
    			}
    			
    			Collections.sort(p, (a,b) -> b.y-a.y);
    			
    			int[] tmp = new int[n];
    			int cnt =1;
    			for(int i=0; i<n; i++) {
    				if(i>0 && p.get(i).y != p.get(i-1).y) cnt++;
    				tmp[i] = cnt;
    			}
    			
    			for(int i=0; i<n; i++) {
    				p.get(i).y = tmp[i];
    			}
    			
    			Collections.sort(p, (a,b) -> {
    				if(a.x == b.x) return a.y - b.y;
    				else return a.x-b.x;
    			});
    			
    			tree = new int[4*n];
    			long res = 0;
    			for(int i=0; i<n; i++) {
    				res += query(1, n, 1, 1, p.get(i).y);
    				update(1, n, 1, p.get(i).y);
    			}
    			System.out.println(res);
    		}
    	}
    	
    	static void update(int s, int e, int node, int idx) {
    		if(idx < s || e < idx) return;
    		tree[node] += 1;
    		if(s == e) return;
    		int mid = (s+e)/2;
    		update(s, mid, node*2, idx);
    		update(mid+1, e, node*2+1, idx);
    	}
    	
    	static int query(int s, int e, int node, int l ,int r) {
    		if(e < l || r < s) return 0;
    		if(l <= s && e <= r) return tree[node];
    		int mid = (s+e)/2;
    		return query(s, mid, node*2, l, r) + query(mid+1, e, node*2+1, l, r);
    	}
    }