https://www.acmicpc.net/problem/12746
[알고리즘 분류]
LCA
Topological Sort
DP
웰노운 비빔밥 문제다.
먼저, 트리 위의 경로는 LCA를 이용하여 두 경로의 합으로 쪼갤 수 있다. 이 위에 값을 1씩 올려주는 과정은 imos법을 사용하면 된다. 아래에서 위로 올려주며 값을 더해줄 것이다. 이렇게 하기 위해서는 정점 \(u\)와 정점 \(v\)에 \(1\)을 더해주고, \(lca(u, v)\)에는 \(-2\)를 더해주면 된다.
트리의 루트로 올라가는 간선으로 트리를 재구성하고, 누적 합을 구해주자. 간선 \(u\rightarrow par_u\)을 지나는 사람들의 수는, \(dp[u]\)에 들어있게 된다. 이들 중 최댓값에 해당하며, 사전 순으로 최소인 간선을 열심히 찾으면 된다.
정답 코드는 다음과 같다.
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
|
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ld, ld> pdd;
//const ld eps = 1e-9;
const ll mod = 998244353;
const ll inf = 1e9;
#define all(v) (v).begin(),(v).end()
#define compress(v) sort(all(v)), (v).erase(unique(all(v)), (v).end())
#define X first
#define Y second
#define fastio ios_base::sync_with_stdio(false);cin.tie(nullptr)
#define MAX(a, b) a = (((a)<(b))?(b):(a))
#define MIN(a, b) a = (((a)>(b))?(b):(a))
// end of def
ll dp[232323];
map<pii, int> dpp;
vector<int> g[232323];
vector<int> g2[232323];
vector<pii> edge;
int par[232323];
int ind[232323];
int dep[232323];
int sp[19][232323];
void dfs(int x, int b){
par[x] = b;
dep[x] = dep[b] + 1;
for (int i: g[x]){
if (i == b) continue;
dfs(i, x);
}
}
void init(int sz){
for (int i=1;i<=sz;i++) sp[0][i] = par[i];
for (int i=1;i<19;i++){
for (int j=1;j<=sz;j++){
sp[i][j] = sp[i-1][sp[i-1][j]];
}
}
for (int i=1;i<=sz;i++){
ind[par[i]]++;
if (par[i]) g2[i].emplace_back(par[i]);
}
}
int qry(int u, int v){
if (dep[u] > dep[v]) swap(u, v);
int go = dep[v] - dep[u];
for (int i=18;i>=0;i--){
if (go >= (1 << i)){
go -= 1 << i;
v = sp[i][v];
}
}
if (u == v) return u;
for (int i=18;i>=0;i--){
if (sp[i][u] == sp[i][v]) continue;
u = sp[i][u];
v = sp[i][v];
}
return sp[0][v];
}
void add(int u, int v){
edge.emplace_back(u,v);
int p = qry(u, v);
dp[u]++; dp[v]++; dp[p]-=2;
}
void ts(int sz){
deque<int> dq;
for (int i=1;i<=sz;i++) if (!ind[i]) {
dq.emplace_back(i);
}
while (!dq.empty()){
int x = dq.front();
dq.pop_front();
for (int i: g2[x]){
int fi=i,se=x;
if (fi>se) swap(fi,se);
dp[i] += dp[x];
dpp[{fi,se}] = dp[x];
if (!(--ind[i])){
dq.emplace_back(i);
}
}
}
}
int main() {
fastio;
int n,m;cin>>n>>m;
for (int i=1;i<n;i++){
int u,v;cin>>u>>v;
g[u].emplace_back(v);
g[v].emplace_back(u);
}
dfs(1, 0);
init(n);
while (m--){
int u,v;cin>>u>>v;
add(u,v);
}
ts(n);
//for (int i=1;i<=n;i++) cout<<dp[i]<<" "; cout<<endl;
m = 0;
for (auto [i,j]: dpp) MAX(m, j);
vector<pii> cand;
for (auto[i,j]:dpp)if (j == m) cand.emplace_back(i);
sort(all(cand));
pll ans = cand[0];
cout << ans.X << " " << ans.Y << " " << m << endl;
return 0;
}
|
cs |
'백준 문제풀이' 카테고리의 다른 글
최근 푼 재밌는 문제들 (2) | 2023.01.01 |
---|---|
백준 1376 - 민식우선탐색 (0) | 2022.12.15 |
백준 23750 - Leader-based Team Distribution (2) | 2022.12.12 |
2022 ICPC Seoul Regional Problem C. Empty Quadrilaterals (5) | 2022.11.21 |
백준 20306 - 블랙홀 (1) | 2022.11.12 |