백준16698 Trees Gump

문제 링크

  • https://icpc.me/16698

문제 출처

  • 2018 CERC G번

사용 알고리즘

  • 볼록 껍질

시간복잡도

  • $O(N^2 \log N)$

풀이

각 서브 트리를 볼록 껍질의 연속한 구간에 배정할 수 있습니다.
DFS를 하면서 각 정점을 방문할 때마다 매번 볼록 껍질을 다시 구하면 $O(N^2 \log N)$ 시간에 문제를 해결할 수 있습니다.

전체 코드

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
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct Point{
    ll x, y, i;
    Point() = default;
    Point(ll x, ll y, ll i) : x(x), y(y), i(i) {}
    bool operator < (const Point &p) const { return tie(x,y) < tie(p.x,p.y); }
    Point operator + (const Point &p) const { return Point(x+p.x, y+p.y, 0); }
    Point operator - (const Point &p) const { return Point(x-p.x, y-p.y, 0); }
    ll operator * (const Point &p) const { return x*p.x + y*p.y; }
    ll operator / (const Point &p) const { return x*p.y - y*p.x; }
};
ll CCW(const Point &p1, const Point &p2, const Point &p3){ return (p2 - p1) / (p3 - p2); }
ll Dist(const Point &p1, const Point &p2){ return (p2 - p1) * (p2 - p1); }

int N, S[1010], E[1010], Size[1010], R[1010];
vector<int> G[1010];
vector<Point> V;

int GetSize(int v, int b){
    Size[v] = 1;
    for(auto i : G[v]) if(i != b) Size[v] += GetSize(i, v);
    return Size[v];
}

void DFS(int v, int b, vector<Point> points){
    swap(points[0], *min_element(points.begin(), points.end()));
    sort(points.begin()+1, points.end(), [&](const Point &a, const Point &b){
        if(auto dir=CCW(points[0], a, b); dir != 0) return dir > 0;
        return Dist(points[0], a) < Dist(points[0], b);
    });
    R[v] = points[0].i;
    int idx = 1;
    for(auto i : G[v]){
        if(i == b) continue;
        vector<Point> nxt(points.begin()+idx, points.begin()+idx+Size[i]);
        idx += Size[i];
        DFS(i, v, nxt);
    }
}

int main(){
    ios_base::sync_with_stdio(false); cin.tie(nullptr);
    cin >> N; V.resize(N);
    for(int i=1; i<N; i++) cin >> S[i] >> E[i], G[S[i]].push_back(E[i]), G[E[i]].push_back(S[i]);
    for(int i=0; i<N; i++) cin >> V[i].x >> V[i].y, V[i].i = i;
    assert(GetSize(0, -1) == N);
    DFS(0, -1, V);
    for(int i=1; i<N; i++) cout << R[S[i]] << " " << R[E[i]] << "\n";
}