Emergency Road Queries
National Olympiad — Regional round (2013 season)
Submission name: no112B.cpp
Problem summary
Maintain connectivity of towns as initially snow-covered roads are reopened. Type 1 asks whether two towns are connected; type 2 adds a usable undirected road.
Input
N M, M usable roads, Q, then Q triples type X Y.
Output
One bit string in query order: 1 for connected, 0 otherwise.
Constraints
N≤1000; M≤2N; Q≤1000000. Between 30% and 35% of calls have type 2.
Worked example
An independently prepared example for this explanation.
Input
9 8 1 2 3 4 5 6 7 8 9 5 7 2 8 2 6 9 6 1 1 8 1 6 2 2 7 1 1 4 7 2 2 3 1 4 7
Output
1001
Solution analysis
- Connectivity components only merge because no road closes again. A disjoint-set union structure maintains a representative for each component.
- Initialize singleton sets and unite every initial road. For a reopening, unite its endpoints; for a query, compare their representatives. Union by size and path compression keep these operations nearly constant in amortized time.
- In the sample, 1 and 8 are initially connected, but 6 and 2 are not. Reopening 7–1 changes nothing. Towns 4 and 7 become connected only after reopening 2–3, giving the bit string 1001.
Why it works
Initially the sets are exactly the connected components after processing all initial edges. An added road merges precisely its endpoint components, preserving that invariant. Therefore equal representatives are equivalent to reachability at each query time.
Watch out. Do not answer only direct adjacency. Duplicate roads are harmless, and a town is connected to itself.
Commented C++17 solution
An independently written complete program with standard headers.
#include<iostream>
#include<vector>
#include<numeric>
#include<algorithm>
// Algorithm: Connectivity components only merge because no road closes again.
using namespace std;
struct DisjointSet{
vector<int>parent;
vector<int>size;
explicit DisjointSet(int n):parent(n+1),size(n+1,1){
iota(parent.begin(),parent.end(),0);
}
int find(int vertex){
while(vertex!=parent[vertex]){
parent[vertex]=parent[parent[vertex]];
vertex=parent[vertex];
}
return vertex;
}
void unite(int a,int b){
a=find(a);
b=find(b);
if(a==b){
return;
}
if(size[a]<size[b]){
swap(a,b);
}
parent[b]=a;
size[a]+=size[b];
}
};
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int towns,roads;
cin>>towns>>roads;
DisjointSet components(towns);
for(int i=0;i<roads;i++){
int a,b;
cin>>a>>b;
components.unite(a,b);
}
int calls;
cin>>calls;
while(calls--){
int type,a,b;
cin>>type>>a>>b;
if(type==2){
components.unite(a,b);
}
else{
cout<<(components.find(a)==components.find(b)?'1':'0');
}
}
cout<<'\n';
}