#include <bits/stdc++.h>
using namespace std;
// --- GEOMETRIC STRUCTURES ---
class Rectangle {
public :
int id;
double minX, minY, maxX, maxY;
// The core geometric relation check
bool intersects( const Rectangle& other) const {
return ! ( minX > other.maxX || maxX < other.minX ||
minY > other.maxY || maxY < other.minY ) ;
}
} ;
// --- PROVIDED TREE LIBRARY (Simulated with Vector) ---
class GeoTree {
private :
// Internal storage simulating the Tree's dataset
vector< Rectangle> treeData;
public :
/**
* Requirement: Add operation takes O(log n) in a real tree.
* Here we use push_back for the simulation.
*/
void addRectangle( int id, Rectangle r) {
r.id = id;
treeData.push_back ( r) ;
}
/**
* Requirement: Query operation takes O(log n) in a real tree.
* In a real library, this would only visit branches that overlap with q.
*/
vector< int > queryRectangle( Rectangle q) {
vector< int > results;
for ( const auto & rect : treeData) {
if ( rect.intersects ( q) ) {
results.push_back ( rect.id ) ;
}
}
return results;
}
} ;
class ComplexPolygon
{
public :
int id;
Rectangle bBox;
vector< pair< int ,int >> vertices;
} ;
bool performPreciseIntersection( const ComplexPolygon& polyA, const ComplexPolygon& polyB) {
// Simulation: returning true for precise intersection
return true ;
}
void mapCase1 ( vector< Rectangle> uscities,vector< Rectangle> largeTableBPartition)
{
GeoTree geotree;
for ( auto city : uscities )
{
geotree.addRectangle ( city.id ,city) ;
}
for ( auto trip : largeTableBPartition )
{
vector< int > visitedCities = geotree.queryRectangle ( trip) ;
for ( auto city : visitedCities )
{
cout << "Intersecting cities for trip :" << trip.id << " are :" << city<< "\n " ;
}
}
}
//Case 2:
vector< pair< int , int >> runFilterJob( vector< Rectangle> & broadcastBBoxesA,
vector< ComplexPolygon> & partitionB) {
GeoTree geotree;
// Build the tree using only Bounding Boxes to stay within memory limits
for ( auto box : broadcastBBoxesA) {
geotree.addRectangle ( box.id , box) ;
}
vector< pair< int , int >> candidates;
for ( auto polyB : partitionB) {
// Fast search in the tree
vector< int > matches = geotree.queryRectangle ( polyB.bBox ) ;
for ( int idA : matches) {
candidates.push_back ( { idA, polyB.id } ) ;
}
}
return candidates;
}
//CASe 2
/**
* JOB 2: REFINEMENT
* This version only loads objects into memory if they are in the candidate list.
*/
void runRefineJob( vector< pair< int , int >> candidates,
vector< ComplexPolygon> tableA_Storage,
vector< ComplexPolygon> tableB_Storage) {
// 1. Identify which IDs we actually need to load (The Filtered Set)
unordered_set< int > requiredA;
unordered_set< int > requiredB;
for ( auto pair : candidates) {
requiredA.insert ( pair.first ) ;
requiredB.insert ( pair.second ) ;
}
// 2. Load ONLY the required heavy objects into our maps
// In a real system, this is the "Shuffle" where only specific rows move over the network.
unordered_map< int , ComplexPolygon> mapA;
unordered_map< int , ComplexPolygon> mapB;
for ( auto a : tableA_Storage) {
if ( requiredA.count ( a.id ) ) mapA[ a.id ] = a;
}
for ( auto b : tableB_Storage) {
if ( requiredB.count ( b.id ) ) mapB[ b.id ] = b;
}
cout << "\n --- Starting Refine Job (Candidate-Only Memory) ---" << endl;
cout << "Memory Usage: Loaded " << mapA.size ( ) << " objects from A instead of " << tableA_Storage.size ( ) << endl;
// 3. Perform the heavy math only on the filtered candidates
for ( auto pair : candidates) {
// Double check existence in map (safety)
if ( mapA.count ( pair.first ) && mapB.count ( pair.second ) ) {
if ( performPreciseIntersection( mapA[ pair.first ] , mapB[ pair.second ] ) ) {
cout << ">>> CONFIRMED: City " << pair.first << " intersects Trip " << pair.second << endl;
}
}
}
}
int main( ) {
// TABLE A: Small Table (e.g., US City Boundaries)
vector< Rectangle> cities1 = {
{ 1 , 0.0 , 0.0 , 5.0 , 5.0 } ,
{ 2 , 10.0 , 10.0 , 15.0 , 15.0 }
} ;
// TABLE B: Large Table Partition (e.g., Uber Trips on local node)
vector< Rectangle> trips1 = {
{ 101 , 2.0 , 2.0 , 3.0 , 3.0 } ,
{ 102 , 4.0 , 4.0 , 6.0 , 6.0 } ,
{ 103 , 12.0 , 12.0 , 18.0 , 18.0 } ,
{ 104 , 20.0 , 20.0 , 25.0 , 25.0 }
} ;
mapCase1( cities1, trips1) ;
vector< ComplexPolygon> cities = {
{ 1 , { 1 , 0.0 , 0.0 , 5.0 , 5.0 } , { { 0.0 , 0.0 } , { 5.0 , 5.0 } } } ,
{ 2 , { 2 , 10.0 , 10.0 , 15.0 , 15.0 } , { { 10.0 , 10.0 } , { 15.0 , 15.0 } } }
} ;
// TABLE B: Large Partition of complex objects
vector< ComplexPolygon> trips = {
{ 101 , { 101 , 2.0 , 2.0 , 3.0 , 3.0 } , { { 2.0 , 2.0 } , { 3.0 , 3.0 } } } ,
{ 102 , { 102 , 12.0 , 12.0 , 14.0 , 14.0 } , { { 12.0 , 12.0 } , { 14.0 , 14.0 } } }
} ;
// 1. EXECUTE FILTER JOB
// Extracting just the Bounding Boxes to broadcast them to mappers
vector< Rectangle> bboxes;
for ( auto c : cities) bboxes.push_back ( c.bBox ) ;
vector< pair< int , int >> candidates = runFilterJob( bboxes, trips) ;
// 2. EXECUTE REFINE JOB
// Perform heavy math only on candidate pairs
runRefineJob( candidates, cities, trips) ;
return 0 ;
}
I2luY2x1ZGUgPGJpdHMvc3RkYysrLmg+Cgp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKLy8gLS0tIEdFT01FVFJJQyBTVFJVQ1RVUkVTIC0tLQoKY2xhc3MgUmVjdGFuZ2xlIHsKCXB1YmxpYzoKICAgIGludCBpZDsKICAgIGRvdWJsZSBtaW5YLCBtaW5ZLCBtYXhYLCBtYXhZOwoKICAgIC8vIFRoZSBjb3JlIGdlb21ldHJpYyByZWxhdGlvbiBjaGVjawogICAgYm9vbCBpbnRlcnNlY3RzKGNvbnN0IFJlY3RhbmdsZSYgb3RoZXIpIGNvbnN0IHsKICAgICAgICByZXR1cm4gIShtaW5YID4gb3RoZXIubWF4WCB8fCBtYXhYIDwgb3RoZXIubWluWCB8fCAKICAgICAgICAgICAgICAgICBtaW5ZID4gb3RoZXIubWF4WSB8fCBtYXhZIDwgb3RoZXIubWluWSk7CiAgICB9Cn07CgovLyAtLS0gUFJPVklERUQgVFJFRSBMSUJSQVJZIChTaW11bGF0ZWQgd2l0aCBWZWN0b3IpIC0tLQoKY2xhc3MgR2VvVHJlZSB7CnByaXZhdGU6CiAgICAvLyBJbnRlcm5hbCBzdG9yYWdlIHNpbXVsYXRpbmcgdGhlIFRyZWUncyBkYXRhc2V0CiAgICB2ZWN0b3I8UmVjdGFuZ2xlPiB0cmVlRGF0YTsKCnB1YmxpYzoKICAgIC8qKgogICAgICogUmVxdWlyZW1lbnQ6IEFkZCBvcGVyYXRpb24gdGFrZXMgTyhsb2cgbikgaW4gYSByZWFsIHRyZWUuCiAgICAgKiBIZXJlIHdlIHVzZSBwdXNoX2JhY2sgZm9yIHRoZSBzaW11bGF0aW9uLgogICAgICovCiAgICB2b2lkIGFkZFJlY3RhbmdsZShpbnQgaWQsIFJlY3RhbmdsZSByKSB7CiAgICAgICAgci5pZCA9IGlkOwogICAgICAgIHRyZWVEYXRhLnB1c2hfYmFjayhyKTsKICAgIH0KCiAgICAvKioKICAgICAqIFJlcXVpcmVtZW50OiBRdWVyeSBvcGVyYXRpb24gdGFrZXMgTyhsb2cgbikgaW4gYSByZWFsIHRyZWUuCiAgICAgKiBJbiBhIHJlYWwgbGlicmFyeSwgdGhpcyB3b3VsZCBvbmx5IHZpc2l0IGJyYW5jaGVzIHRoYXQgb3ZlcmxhcCB3aXRoIHEuCiAgICAgKi8KICAgIHZlY3RvcjxpbnQ+IHF1ZXJ5UmVjdGFuZ2xlKFJlY3RhbmdsZSBxKSB7CiAgICAgICAgdmVjdG9yPGludD4gcmVzdWx0czsKICAgICAgICBmb3IgKGNvbnN0IGF1dG8mIHJlY3QgOiB0cmVlRGF0YSkgewogICAgICAgICAgICBpZiAocmVjdC5pbnRlcnNlY3RzKHEpKSB7CiAgICAgICAgICAgICAgICByZXN1bHRzLnB1c2hfYmFjayhyZWN0LmlkKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gcmVzdWx0czsKICAgIH0KfTsKCmNsYXNzIENvbXBsZXhQb2x5Z29uCnsKCXB1YmxpYzoKCWludCBpZDsKCVJlY3RhbmdsZSBiQm94OwoJdmVjdG9yPHBhaXI8aW50LGludD4+IHZlcnRpY2VzOwp9OwoKYm9vbCBwZXJmb3JtUHJlY2lzZUludGVyc2VjdGlvbihjb25zdCBDb21wbGV4UG9seWdvbiYgcG9seUEsIGNvbnN0IENvbXBsZXhQb2x5Z29uJiBwb2x5QikgewogICAgLy8gU2ltdWxhdGlvbjogcmV0dXJuaW5nIHRydWUgZm9yIHByZWNpc2UgaW50ZXJzZWN0aW9uCiAgICByZXR1cm4gdHJ1ZTsgCn0KCnZvaWQgbWFwQ2FzZTEgKHZlY3RvcjxSZWN0YW5nbGU+IHVzY2l0aWVzLHZlY3RvcjxSZWN0YW5nbGU+IGxhcmdlVGFibGVCUGFydGl0aW9uKQp7CglHZW9UcmVlIGdlb3RyZWU7Cglmb3IoYXV0byBjaXR5IDp1c2NpdGllcyApCgl7CgkJZ2VvdHJlZS5hZGRSZWN0YW5nbGUoY2l0eS5pZCxjaXR5KTsKCX0KCQoJZm9yKGF1dG8gdHJpcCA6bGFyZ2VUYWJsZUJQYXJ0aXRpb24gKQoJewoJCXZlY3RvcjxpbnQ+IHZpc2l0ZWRDaXRpZXMgPSAJZ2VvdHJlZS5xdWVyeVJlY3RhbmdsZSh0cmlwKTsKCQlmb3IoYXV0byBjaXR5IDogdmlzaXRlZENpdGllcyApCgkJewoJCQljb3V0PDwiSW50ZXJzZWN0aW5nIGNpdGllcyBmb3IgdHJpcCA6Ijw8dHJpcC5pZDw8IiBhcmUgOiIgPDxjaXR5PDwiXG4iOwoJCX0KCQkKCX0KfQovL0Nhc2UgMjoKdmVjdG9yPHBhaXI8aW50LCBpbnQ+PiBydW5GaWx0ZXJKb2IoIHZlY3RvcjxSZWN0YW5nbGU+JiBicm9hZGNhc3RCQm94ZXNBLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY3RvcjxDb21wbGV4UG9seWdvbj4mIHBhcnRpdGlvbkIpIHsKICAgIEdlb1RyZWUgZ2VvdHJlZTsKICAgIAogICAgLy8gQnVpbGQgdGhlIHRyZWUgdXNpbmcgb25seSBCb3VuZGluZyBCb3hlcyB0byBzdGF5IHdpdGhpbiBtZW1vcnkgbGltaXRzCiAgICBmb3IoIGF1dG8gYm94IDogYnJvYWRjYXN0QkJveGVzQSkgewogICAgICAgIGdlb3RyZWUuYWRkUmVjdGFuZ2xlKGJveC5pZCwgYm94KTsKICAgIH0KCiAgICAKCiAgICB2ZWN0b3I8cGFpcjxpbnQsIGludD4+IGNhbmRpZGF0ZXM7CiAgICBmb3IoIGF1dG8gcG9seUIgOiBwYXJ0aXRpb25CKSB7CiAgICAgICAgLy8gRmFzdCBzZWFyY2ggaW4gdGhlIHRyZWUKICAgICAgICB2ZWN0b3I8aW50PiBtYXRjaGVzID0gZ2VvdHJlZS5xdWVyeVJlY3RhbmdsZShwb2x5Qi5iQm94KTsKICAgICAgICBmb3IoaW50IGlkQSA6IG1hdGNoZXMpIHsKICAgICAgICAgICAgY2FuZGlkYXRlcy5wdXNoX2JhY2soe2lkQSwgcG9seUIuaWR9KTsKICAgICAgICB9CiAgICB9CiAgICByZXR1cm4gY2FuZGlkYXRlczsKfQovL0NBU2UgMgovKioKICogSk9CIDI6IFJFRklORU1FTlQKICogVGhpcyB2ZXJzaW9uIG9ubHkgbG9hZHMgb2JqZWN0cyBpbnRvIG1lbW9yeSBpZiB0aGV5IGFyZSBpbiB0aGUgY2FuZGlkYXRlIGxpc3QuCiAqLwp2b2lkIHJ1blJlZmluZUpvYih2ZWN0b3I8cGFpcjxpbnQsIGludD4+IGNhbmRpZGF0ZXMsIAogICAgICAgICAgICAgICAgICB2ZWN0b3I8Q29tcGxleFBvbHlnb24+IHRhYmxlQV9TdG9yYWdlLCAKICAgICAgICAgICAgICAgICAgdmVjdG9yPENvbXBsZXhQb2x5Z29uPiB0YWJsZUJfU3RvcmFnZSkgewogICAgCiAgICAvLyAxLiBJZGVudGlmeSB3aGljaCBJRHMgd2UgYWN0dWFsbHkgbmVlZCB0byBsb2FkIChUaGUgRmlsdGVyZWQgU2V0KQogICAgdW5vcmRlcmVkX3NldDxpbnQ+IHJlcXVpcmVkQTsKICAgIHVub3JkZXJlZF9zZXQ8aW50PiByZXF1aXJlZEI7CiAgICBmb3IgKGF1dG8gcGFpciA6IGNhbmRpZGF0ZXMpIHsKICAgICAgICByZXF1aXJlZEEuaW5zZXJ0KHBhaXIuZmlyc3QpOwogICAgICAgIHJlcXVpcmVkQi5pbnNlcnQocGFpci5zZWNvbmQpOwogICAgfQoKICAgIC8vIDIuIExvYWQgT05MWSB0aGUgcmVxdWlyZWQgaGVhdnkgb2JqZWN0cyBpbnRvIG91ciBtYXBzCiAgICAvLyBJbiBhIHJlYWwgc3lzdGVtLCB0aGlzIGlzIHRoZSAiU2h1ZmZsZSIgd2hlcmUgb25seSBzcGVjaWZpYyByb3dzIG1vdmUgb3ZlciB0aGUgbmV0d29yay4KICAgIHVub3JkZXJlZF9tYXA8aW50LCBDb21wbGV4UG9seWdvbj4gbWFwQTsKICAgIHVub3JkZXJlZF9tYXA8aW50LCBDb21wbGV4UG9seWdvbj4gbWFwQjsKCiAgICBmb3IgKGF1dG8gYSA6IHRhYmxlQV9TdG9yYWdlKSB7CiAgICAgICAgaWYgKHJlcXVpcmVkQS5jb3VudChhLmlkKSkgbWFwQVthLmlkXSA9IGE7CiAgICB9CiAgICBmb3IgKGF1dG8gYiA6IHRhYmxlQl9TdG9yYWdlKSB7CiAgICAgICAgaWYgKHJlcXVpcmVkQi5jb3VudChiLmlkKSkgbWFwQltiLmlkXSA9IGI7CiAgICB9CgogICAgCgogICAgY291dCA8PCAiXG4tLS0gU3RhcnRpbmcgUmVmaW5lIEpvYiAoQ2FuZGlkYXRlLU9ubHkgTWVtb3J5KSAtLS0iIDw8IGVuZGw7CiAgICBjb3V0IDw8ICJNZW1vcnkgVXNhZ2U6IExvYWRlZCAiIDw8IG1hcEEuc2l6ZSgpIDw8ICIgb2JqZWN0cyBmcm9tIEEgaW5zdGVhZCBvZiAiIDw8IHRhYmxlQV9TdG9yYWdlLnNpemUoKSA8PCBlbmRsOwoKICAgIC8vIDMuIFBlcmZvcm0gdGhlIGhlYXZ5IG1hdGggb25seSBvbiB0aGUgZmlsdGVyZWQgY2FuZGlkYXRlcwogICAgZm9yIChhdXRvIHBhaXIgOiBjYW5kaWRhdGVzKSB7CiAgICAgICAgLy8gRG91YmxlIGNoZWNrIGV4aXN0ZW5jZSBpbiBtYXAgKHNhZmV0eSkKICAgICAgICBpZiAobWFwQS5jb3VudChwYWlyLmZpcnN0KSAmJiBtYXBCLmNvdW50KHBhaXIuc2Vjb25kKSkgewogICAgICAgICAgICBpZiAocGVyZm9ybVByZWNpc2VJbnRlcnNlY3Rpb24obWFwQVtwYWlyLmZpcnN0XSwgbWFwQltwYWlyLnNlY29uZF0pKSB7CiAgICAgICAgICAgICAgICBjb3V0IDw8ICI+Pj4gQ09ORklSTUVEOiBDaXR5ICIgPDwgcGFpci5maXJzdCA8PCAiIGludGVyc2VjdHMgVHJpcCAiIDw8IHBhaXIuc2Vjb25kIDw8IGVuZGw7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9Cn0KaW50IG1haW4oKSB7CiAgICAvLyBUQUJMRSBBOiBTbWFsbCBUYWJsZSAoZS5nLiwgVVMgQ2l0eSBCb3VuZGFyaWVzKQogICAgdmVjdG9yPFJlY3RhbmdsZT4gY2l0aWVzMSA9IHsKICAgICAgICB7MSwgMC4wLCAwLjAsIDUuMCwgNS4wfSwgICAKICAgICAgICB7MiwgMTAuMCwgMTAuMCwgMTUuMCwgMTUuMH0gCiAgICB9OwoKICAgIC8vIFRBQkxFIEI6IExhcmdlIFRhYmxlIFBhcnRpdGlvbiAoZS5nLiwgVWJlciBUcmlwcyBvbiBsb2NhbCBub2RlKQogICAgdmVjdG9yPFJlY3RhbmdsZT4gdHJpcHMxID0gewogICAgICAgIHsxMDEsIDIuMCwgMi4wLCAzLjAsIDMuMH0sICAgCiAgICAgICAgezEwMiwgNC4wLCA0LjAsIDYuMCwgNi4wfSwgICAKICAgICAgICB7MTAzLCAxMi4wLCAxMi4wLCAxOC4wLCAxOC4wfSwgCiAgICAgICAgezEwNCwgMjAuMCwgMjAuMCwgMjUuMCwgMjUuMH0gIAogICAgfTsKCiAgICBtYXBDYXNlMShjaXRpZXMxLCB0cmlwczEpOwogICAgdmVjdG9yPENvbXBsZXhQb2x5Z29uPiBjaXRpZXMgPSB7CiAgICAgICAgezEsIHsxLCAwLjAsIDAuMCwgNS4wLCA1LjB9LCB7ezAuMCwgMC4wfSwgezUuMCwgNS4wfX19LCAKICAgICAgICB7MiwgezIsIDEwLjAsIDEwLjAsIDE1LjAsIDE1LjB9LCB7ezEwLjAsIDEwLjB9LCB7MTUuMCwgMTUuMH19fQogICAgfTsKCiAgICAvLyBUQUJMRSBCOiBMYXJnZSBQYXJ0aXRpb24gb2YgY29tcGxleCBvYmplY3RzCiAgICB2ZWN0b3I8Q29tcGxleFBvbHlnb24+IHRyaXBzID0gewogICAgICAgIHsxMDEsIHsxMDEsIDIuMCwgMi4wLCAzLjAsIDMuMH0sIHt7Mi4wLCAyLjB9LCB7My4wLCAzLjB9fX0sCiAgICAgICAgezEwMiwgezEwMiwgMTIuMCwgMTIuMCwgMTQuMCwgMTQuMH0sIHt7MTIuMCwgMTIuMH0sIHsxNC4wLCAxNC4wfX19CiAgICB9OwoKICAgIC8vIDEuIEVYRUNVVEUgRklMVEVSIEpPQgogICAgLy8gRXh0cmFjdGluZyBqdXN0IHRoZSBCb3VuZGluZyBCb3hlcyB0byBicm9hZGNhc3QgdGhlbSB0byBtYXBwZXJzCiAgICB2ZWN0b3I8UmVjdGFuZ2xlPiBiYm94ZXM7CiAgICBmb3IgKGF1dG8gYyA6IGNpdGllcykgYmJveGVzLnB1c2hfYmFjayhjLmJCb3gpOwogICAgCiAgICB2ZWN0b3I8cGFpcjxpbnQsIGludD4+IGNhbmRpZGF0ZXMgPSBydW5GaWx0ZXJKb2IoYmJveGVzLCB0cmlwcyk7CgogICAgCgogICAgLy8gMi4gRVhFQ1VURSBSRUZJTkUgSk9CCiAgICAvLyBQZXJmb3JtIGhlYXZ5IG1hdGggb25seSBvbiBjYW5kaWRhdGUgcGFpcnMKICAgIHJ1blJlZmluZUpvYihjYW5kaWRhdGVzLCBjaXRpZXMsIHRyaXBzKTsKCiAgICByZXR1cm4gMDsKfQ==