본문 바로가기

Problem Solving/문제풀이

[BOJ] 2472 체인점

굉장한 학생 문제랑 다익스트라의 짬뽕이다. 덕분에 코드가 장난아니게 길다.

각 정점이 최대 5개의 간선을 가지니 다익스트라의 $O(ElgV)$ 시간복잡도가 $O(VlgV)$로 바뀐다. 그러면 주어진 세 정점에 대해서 다익스트라를 한번씩 돌려볼 수 있고, 모든 정점에 대해 주어진 세 정점으로부터 각 정점으로부터의 거리 $dist_i$가 나오게 된다. 거리의 범위는 크지만 대소관계만을 비교하면 되므로 등위를 정렬을 통해 다시 매겨주자. 그러면 굉장한 학생 문제처럼 모든 정점에 대해 체인점을 세울수 있음/없음을 판별할 수 있다. 그 이후 들어오는 쿼리는 $O(1)$에 처리 가능하다.

 수행 시간은 다익스트라, 정렬, RMQ 등이 다 섞여서 결과적으로 $O(NlgN)$이다. 개인적으로 문제 자체도 굉장한 학생 문제를 모르면 접근하기 힘들고, 코딩 자체도 꽤나 까다로웠다고 생각함. 푸는 동안 재밌긴 했는데 다시 풀라고 하면 못 풀것 같다. ㅠㅠ


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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <tuple>
#include <cmath>
 
using namespace std;
 
const int INF=1e9+7;
int n,m,t;
int a[3];
 
typedef vector<int> vi;
typedef pair<int,int> pii;
typedef tuple<int,int,int,int> tp;
 
vector<vector<pii> > adj;
 
vi dijkstra(int st)
{
    vi dist(n+1,INF);
    priority_queue<pair<int,int> > Q;
    Q.push(make_pair(0,st));
    dist[st]=0;
    while(!Q.empty())
    {
        int hdist=-Q.top().first;
        int here=Q.top().second;
        Q.pop();
        if(hdist>dist[here]) continue;
        for(int i=0;i<adj[here].size();i++)
        {
            int there=adj[here][i].first;
            int tdist=adj[here][i].second+hdist;
            if(tdist>dist[there]) continue;
            dist[there]=tdist;
            Q.push(make_pair(-tdist,there));
        }
    }
    return dist;
}
 
typedef struct SegmentTree
{
    int n;
    vi tree;
    SegmentTree(int dn) :n(dn)
    {
        int tree_height=(int)ceil(log2(n));
        int tree_size=(1<<(tree_height+1));
        tree.assign(tree_size,INF);
    }
    void update(int st, int en, int idx, int node, int diff)
    {
        if(idx<st || en<idx) return;
        else if(st==en && st==idx)
        {
            tree[node]=diff;
            return;
        }
        int mid=(st+en)>>1;
        update(st,mid,idx,node*2,diff);
        update(mid+1,en,idx,node*2+1,diff);
        tree[node]=min(tree[node*2],tree[node*2+1]);
    }
    void update(int idx, int diff)
    {
        update(0,n-1,idx,1,diff);
    }
    int query(int st, int en, int le, int ri, int node)
    {
        if(ri<st || en<le) return INF;
        if(le<=st && en<=ri) return tree[node];
        int mid=(st+en)>>1;
        return min(query(st,mid,le,ri,node*2),query(mid+1,en,le,ri,node*2+1));
    }
    int query(int le, int ri)
    {
        return query(0,n-1,le,ri,1);
    }
}RMQ;
 
bool cmp(pii a, pii b)
{
    if(a.second==b.second) return a.first<b.first;
        else return a.second<b.second;
}
 
int main()
{
    scanf("%d",&n);
    for(int i=0;i<3;i++scanf("%d",&a[i]);
    scanf("%d",&m);
    adj.assign(n+1,vector<pii>());
    for(int i=0;i<m;i++)
    {
        int t1,t2,tw;
        scanf("%d %d %d",&t1,&t2,&tw);
        adj[t1].push_back(make_pair(t2,tw));
        adj[t2].push_back(make_pair(t1,tw));
    }
    vi dist[3];
    for(int i=0;i<3;i++) dist[i]=dijkstra(a[i]);
 
    vector<pii> st[3];
    vi ra[3]; //등위를 저장
    for(int i=0;i<3;i++)
    {
        ra[i].assign(n+1,0);
        for(int j=1;j<=n;j++)
            st[i].push_back(make_pair(j,dist[i][j]));
        sort(st[i].begin(),st[i].end(),cmp);
        for(int j=0;j<st[i].size();j++)
            ra[i][st[i][j].first]=j;
 
    }
 
    vector<tp> VT;
    for(int i=1;i<=n;i++)
        VT.push_back(tie(ra[0][i],ra[1][i],ra[2][i],i));
    sort(VT.begin(),VT.end());
 
    vi okay(n+1);
    RMQ Q(n+1);
    for(int i=0;i<n;i++)
    {
        int da=get<0>(VT[i]), db=get<1>(VT[i]), dc=get<2>(VT[i]);
        int idx=get<3>(VT[i]);
        Q.update(db,dc);
        int mi=Q.query(0,db);
        if(mi<dc) okay[idx]=-1;
        else okay[idx]=1;
    }
 
    int rd;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&rd);
        printf("%s\n",okay[rd]==1?"YES":"NO");
    }
    return 0;
}
 
cs

'Problem Solving > 문제풀이' 카테고리의 다른 글

NYPC 예선 후기  (1) 2018.08.31
[BOJ] 10840 구간 성분  (0) 2018.07.19
[CF] Codeforces Round #464 (Div. 2)  (0) 2018.02.18
[BOJ] 1504 특정한 최단 경로  (0) 2018.02.12
[BOJ] 1916 최소비용 구하기  (0) 2018.02.12