Skip to content

Commit 3d2a737

Browse files
authored
Document LightOJ 1101 – A Secret Mission
Added problem summary, key observation, strategy, complexity analysis, and implementation details for LightOJ 1101.
1 parent c35ba79 commit 3d2a737

1 file changed

Lines changed: 235 additions & 0 deletions

File tree

1101/en.md

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,236 @@
1+
# LightOJ 1101 – A Secret Mission
12

3+
## Problem Summary
4+
5+
We are given a connected weighted graph with (N) cities and (M) roads.
6+
Each road has a *danger value*.
7+
8+
For each query (s, t), we must find a path from (s) to (t) such that:
9+
10+
> the maximum danger of any road on the path is minimized.
11+
12+
This is known as a **minimax path problem**.
13+
14+
---
15+
16+
## Key Observation
17+
18+
If we build a **Minimum Spanning Tree (MST)** of the graph, then:
19+
20+
> For any two nodes, the path between them in the MST minimizes the maximum edge weight among all possible paths in the original graph.
21+
22+
This is a well-known property of MSTs.
23+
Therefore, once we construct the MST, we only need to answer queries on that tree.
24+
25+
---
26+
27+
## Strategy
28+
29+
1. Build the MST using **Prim’s algorithm**
30+
2. Convert the graph into a tree
31+
3. Preprocess the tree using **Binary Lifting**
32+
4. Store:
33+
34+
* `anc[u][i]` → (2^i)-th ancestor of node (u)
35+
* `mx[u][i]` → maximum edge weight from (u) to its (2^i)-th ancestor
36+
5. For each query:
37+
38+
* compute LCA of (u) and (v)
39+
* find maximum edge on path (u to LCA) and (v to LCA) using binary lifting
40+
* answer = max of the two above values.
41+
42+
---
43+
44+
## Complexity
45+
46+
* MST construction: (O(M log N))
47+
* Binary lifting preprocessing: (O(N log N))
48+
* Each query: (O(log N))
49+
50+
This easily fits within constraints.
51+
52+
---
53+
54+
## Implementation
55+
56+
```cpp
57+
#include<bits/stdc++.h>
58+
using namespace std;
59+
#define br cout<<"\n";
60+
#define ll long long
61+
#define loop(n) for(int i=0; i<(n); i++)
62+
#define fr(i,init, n) for(int i=(init); i<(n); i++)
63+
#define revl(i,init) for(int i=(init-1); i>=0; i--)
64+
#define pb push_back
65+
#define all(v) v.begin(),v.end()
66+
#define nl "\n"
67+
68+
69+
const int N = 50005, LOG=18 ;
70+
vector<pair<int,int>> adj2[N], adj[N];
71+
bool vis[N];
72+
int anc[N][LOG], mx[N][LOG], dep[N];
73+
74+
75+
// clear global variables for each test case
76+
void clear(){
77+
loop(N){
78+
vis[i] = false;
79+
adj2[i].clear();
80+
adj[i].clear();
81+
}
82+
memset(anc,0, sizeof(anc));
83+
memset(mx, 0, sizeof(mx));
84+
memset(dep, 0, sizeof(dep));
85+
}
86+
87+
// create the MST from adj2[] and build the new one in adj[]
88+
void createMST(){
89+
90+
priority_queue<
91+
tuple<int,int,int>,
92+
vector<tuple<int,int,int>>,
93+
greater<tuple<int,int,int>>
94+
> pq;
95+
96+
pq.push({-1, 1,0});
97+
98+
while(! pq.empty()){
99+
int wt, node, parent;
100+
tie(wt, node, parent) = pq.top();
101+
pq.pop();
102+
103+
if(vis[node]) continue;
104+
105+
vis[node] = true;
106+
107+
if(parent!=0){
108+
adj[parent].pb({node,wt});
109+
adj[node].pb({parent,wt});
110+
}
111+
112+
113+
for(auto child: adj2[node]){
114+
if(!vis[child.first]){
115+
pq.push({child.second, child.first, node});
116+
}
117+
}
118+
}
119+
120+
}
121+
122+
// dfs for binary-lifting precomputations
123+
void dfs(int node, int par=0, int wt=0){
124+
125+
dep[node] = dep[par]+1;
126+
anc[node][0] = par;
127+
128+
mx[node][0]= wt;
129+
130+
fr(i,1,LOG){
131+
anc[node][i] = anc[ anc[node][i-1] ][i-1];
132+
mx[node][i] = max( mx[ anc[node][i-1] ][i-1] , mx[node][i-1] );
133+
}
134+
135+
for(auto child: adj[node]){
136+
if(child.first != par){
137+
dfs(child.first, node, child.second);
138+
}
139+
}
140+
}
141+
142+
int lca(int u, int v){
143+
if(dep[u]< dep[v]) swap(u,v);
144+
145+
revl(i,LOG){
146+
if( dep[ anc[u][i] ] >= dep[v] ){
147+
u = anc[u][i];
148+
}
149+
}
150+
151+
if(u==v) return u;
152+
153+
revl(i,LOG){
154+
if(anc[u][i] != anc[v][i]){
155+
u = anc[u][i];
156+
v = anc[v][i];
157+
}
158+
}
159+
160+
return anc[u][0];
161+
162+
}
163+
164+
// maximum edge between a node and its ancestor
165+
int maxedge(int node, int l){
166+
int dis = dep[node] - dep[l];
167+
168+
int ans = 0;
169+
170+
revl(i,LOG){
171+
if(dis & (1<<i)){
172+
ans = max( ans, mx[node][i] );
173+
node= anc[node][i];
174+
}
175+
}
176+
177+
return ans;
178+
179+
}
180+
181+
int query(int u, int v){
182+
183+
int l = lca(u,v);
184+
185+
return max( maxedge(u,l), maxedge(v,l) );
186+
187+
}
188+
189+
190+
191+
int tc = 1;
192+
void SOLVE(){
193+
clear();
194+
cout<<"Case "<<tc++<<":"<<nl;
195+
196+
int n,m; cin>>n>>m;
197+
while(m--){
198+
int a,b,c; cin>>a>>b>>c;
199+
adj2[a].pb({b,c});
200+
adj2[b].pb({a,c});
201+
}
202+
203+
createMST();
204+
205+
dfs(1);
206+
207+
int q; cin>>q;
208+
while(q--){
209+
int u,v; cin>>u>>v;
210+
cout<<query(u,v)<<nl;
211+
}
212+
213+
}
214+
215+
signed main(){
216+
ios_base::sync_with_stdio(0);
217+
cin.tie(0);
218+
int t=1;
219+
220+
cin>>t;/////////////////////
221+
222+
while(t--) SOLVE();
223+
return 0;
224+
}
225+
```
226+
227+
---
228+
229+
## References
230+
231+
* https://cp-algorithms.com/graph/mst_prim.html
232+
* https://cp-algorithms.com/graph/lca_binary_lifting.html
233+
234+
---
235+
236+
**Author:** Sadat

0 commit comments

Comments
 (0)