#include <algorithm>
#include <chrono>
#include <cmath>
#include <fstream>
#include <iostream>
#include <queue>
#include <random>
#include <sstream>
#include <tuple>
#include <unordered_map>
#include <vector>
class Node {
public:
Node * left ;
Node * right ;
int y_med ;
std :: vector < int > x_sorted_idx ;
std :: vector < int > left_x_cascading_map ;
std :: vector < int > right_x_cascading_map ;
std :: vector < int > left_x_cascading_map_inverse ;
std :: vector < int > right_x_cascading_map_inverse ;
Node ( int y_med_ , const std :: vector < int >& x_sorted_idx_ )
: y_med ( y_med_ ), x_sorted_idx ( x_sorted_idx_ ) {
left = nullptr ;
right = nullptr ;
}
};
class Tree {
public:
Node * root ;
const std :: vector < std :: vector < int >>& pts ;
std :: vector < int > x_sorted_idx ;
std :: vector < int > y_sorted_idx ;
std :: vector < int > idx_to_y_order ;
int td1 , td2 , td3 , td4 , td5 , td6 ;
Tree ( const std :: vector < std :: vector < int >>& pts_ ) : pts ( pts_ ) {
// TODO: remove O(n) copys using only sort.
std :: chrono :: high_resolution_clock :: time_point begin ;
std :: chrono :: high_resolution_clock :: time_point end ;
std :: chrono :: high_resolution_clock :: time_point tp0 ;
std :: chrono :: high_resolution_clock :: time_point tp1 ;
std :: chrono :: high_resolution_clock :: time_point tp2 ;
int time_diff ;
begin = std :: chrono :: high_resolution_clock :: now ();
// std::vector<std::tuple<int, int, int>> indexed_xy;
// indexed_xy.reserve(pts_.size());
// for (int i = 0; i < pts.size(); i++) {
// indexed_xy.emplace_back(i, pts[i][0], pts[i][1]);
// }
// std::sort(indexed_xy.begin(), indexed_xy.end(),
// [](const auto& a, const auto& b) {
// int a_x;
// std::tie(std::ignore, a_x, std::ignore) = a;
// int b_x;
// std::tie(std::ignore, b_x, std::ignore) = b;
// return a_x < b_x;
// });
// x_sorted_idx.reserve(pts_.size());
// for (const auto& item : indexed_xy) {
// int idx;
// std::tie(idx, std::ignore, std::ignore) = item;
// x_sorted_idx.push_back(idx);
// }
x_sorted_idx . reserve ( pts_ . size ());
// y_sorted_idx.reserve(pts_.size());
for ( int i = 0 ; i < pts_ . size (); i ++ ) {
x_sorted_idx . push_back ( i );
// y_sorted_idx.push_back(i);
}
// x_sorted_idx.resize(pts_.size());
// std::iota(x_sorted_idx.begin(), x_sorted_idx.end(), 0);
tp0 = std :: chrono :: high_resolution_clock :: now ();
y_sorted_idx . reserve ( pts_ . size ());
for ( int i = 0 ; i < pts_ . size (); i ++ ) {
y_sorted_idx . push_back ( i );
}
tp1 = std :: chrono :: high_resolution_clock :: now ();
std :: stable_sort (
y_sorted_idx . begin (), y_sorted_idx . end (),
[ & pts_ ]( int i1 , int i2 ) { return pts_ [ i1 ][ 1 ] < pts_ [ i2 ][ 1 ]; });
// std::stable_sort(indexed_xy.begin(), indexed_xy.end(),
// [](const auto& a, const auto& b) {
// int a_y;
// std::tie(std::ignore, std::ignore, a_y) = a;
// int b_y;
// std::tie(std::ignore, std::ignore, b_y) = b;
// return a_y < b_y;
// });
tp2 = std :: chrono :: high_resolution_clock :: now ();
// y_sorted_idx.reserve(pts_.size());
// idx_to_y_order.resize(indexed_xy.size());
// for (int i = 0; i < indexed_xy.size(); i++) {
// int idx;
// std::tie(idx, std::ignore, std::ignore) = indexed_xy[i];
// idx_to_y_order[idx] = i;
// y_sorted_idx.push_back(idx);
// }
idx_to_y_order . resize ( y_sorted_idx . size ());
for ( int i = 0 ; i < y_sorted_idx . size (); i ++ ) {
idx_to_y_order [ y_sorted_idx [ i ]] = i ;
}
end = std :: chrono :: high_resolution_clock :: now ();
td1 = std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( end - begin )
. count ();
td3 = std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( tp0 - begin )
. count ();
td4 = std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( tp1 - tp0 )
. count ();
td5 = std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( tp2 - tp1 )
. count ();
td6 = std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( end - tp2 )
. count ();
begin = std :: chrono :: high_resolution_clock :: now ();
root = ConstructTree ( x_sorted_idx , 0 , pts . size () - 1 );
end = std :: chrono :: high_resolution_clock :: now ();
td2 = std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( end - begin )
. count ();
}
Node * ConstructTree ( const std :: vector < int >& x_sorted_idx_ , int y_idx_left ,
int y_idx_right ) {
// TODO: remove x_sorted_idx_ parameter using y indices
int y_idx_med = ( y_idx_left + y_idx_right + 1 ) / 2 ;
int y_med = pts [ y_sorted_idx [ y_idx_med ]][ 1 ];
int n = x_sorted_idx_ . size ();
// std::cout << "Tree Construction [" << y_idx_left << " ~ " << y_idx_right
// << "]" << std::endl;
// std::cout << "y med: " << y_med << std::endl;
// for (const auto& idx : x_sorted_idx_) {
// std::cout << "(" << pts[idx][0] << ", " << pts[idx][1] << ") - ";
// }
// std::cout << std::endl;
Node * node = new Node ( y_med , x_sorted_idx_ );
if ( y_idx_left == y_idx_right ) {
return node ;
}
std :: vector < int > x_sorted_idx_left ;
x_sorted_idx_left . reserve ( n );
std :: vector < int > x_sorted_idx_right ;
x_sorted_idx_right . reserve ( n );
std :: vector < int >& left_x_cascading_map = node -> left_x_cascading_map ;
left_x_cascading_map . reserve ( n );
std :: vector < int >& right_x_cascading_map = node -> right_x_cascading_map ;
right_x_cascading_map . reserve ( n );
std :: vector < int >& left_x_cascading_map_inverse =
node -> left_x_cascading_map_inverse ;
left_x_cascading_map_inverse . reserve ( n );
std :: vector < int >& right_x_cascading_map_inverse =
node -> right_x_cascading_map_inverse ;
right_x_cascading_map_inverse . reserve ( n );
int left_cnt = 0 ;
int right_cnt = 0 ;
int left_cnt_inverse = - 1 ;
int right_cnt_inverse = - 1 ;
// 0~size
for ( int i = 0 ; i < x_sorted_idx_ . size (); i ++ ) {
left_x_cascading_map . push_back ( left_cnt );
right_x_cascading_map . push_back ( right_cnt );
int y_order_i = idx_to_y_order [ x_sorted_idx_ [ i ]];
if ( y_order_i < y_idx_med ) {
x_sorted_idx_left . push_back ( x_sorted_idx_ [ i ]);
left_cnt ++ ;
left_cnt_inverse ++ ;
} else {
x_sorted_idx_right . push_back ( x_sorted_idx_ [ i ]);
right_cnt ++ ;
right_cnt_inverse ++ ;
}
left_x_cascading_map_inverse . push_back ( left_cnt_inverse );
right_x_cascading_map_inverse . push_back ( right_cnt_inverse );
}
Node * left_node =
ConstructTree ( x_sorted_idx_left , y_idx_left , y_idx_med - 1 );
Node * right_node =
ConstructTree ( x_sorted_idx_right , y_idx_med , y_idx_right );
node -> left = left_node ;
node -> right = right_node ;
// node->left_x_cascading_map = left_x_cascading_map;
// node->right_x_cascading_map = right_x_cascading_map;
// node->left_x_cascading_map_inverse = left_x_cascading_map_inverse;
// node->right_x_cascading_map_inverse = right_x_cascading_map_inverse;
return node ;
}
int QueryRight ( int qx , int qy ) const {
Node * node = root ;
int bound_x_sorted_idx = LowerBound ( x_sorted_idx , qx );
// if (bound_x_sorted_idx < x_sorted_idx.size() &&
// x_sorted_idx[bound_x_sorted_idx] == qx) {
// bound_x_sorted_idx = UpperBound(x_sorted_idx, qx) + 1;
// }
int closest_right_idx = - 1 ;
while ( node -> left != nullptr && node -> right != nullptr ) {
// std::cout << "----------------" << std::endl;
// std::cout << "y med: " << node->y_med << std::endl;
// std::cout << "lower_bound idx: " << bound_x_sorted_idx <<
// std::endl; std::cout << "x_sorted_idx : \n\t"; for (const auto& idx :
// node->x_sorted_idx) {
// std::cout << idx << " ";
// }
// std::cout << std::endl;
// std::cout << "left_cascading_map : \n\t";
// for (const auto& cascading_idx : node->left_x_cascading_map) {
// std::cout << cascading_idx << " ";
// }
// std::cout << std::endl;
// std::cout << "left->x_sorted_idx : \n\t";
// for (const auto& idx : node->left->x_sorted_idx) {
// std::cout << idx << " ";
// }
// std::cout << std::endl;
// std::cout << "right_cascading_map : \n\t";
// for (const auto& cascading_idx : node->right_x_cascading_map) {
// std::cout << cascading_idx << " ";
// }
// std::cout << std::endl;
// std::cout << "right->x_sorted_idx : \n\t";
// for (const auto& idx : node->right->x_sorted_idx) {
// std::cout << idx << " ";
// }
// std::cout << std::endl;
// std::cout << "left 1, right 0 : " << (qy <= node->y_med) <<
// std::endl; std::cout << "closest_right_idx : " << closest_right_idx
// << std::endl;
if ( bound_x_sorted_idx >= node -> x_sorted_idx . size ()) {
break ;
}
// NOTE
// qy 랑 같은 y 에 멈출지 말지? (output sensitive 관련)
if ( qy < node -> y_med ) {
int found_higher_x_sorted_idx =
node -> right_x_cascading_map [ bound_x_sorted_idx ];
if ( found_higher_x_sorted_idx < node -> right -> x_sorted_idx . size ()) {
int found_higher_idx =
node -> right -> x_sorted_idx [ found_higher_x_sorted_idx ];
if ( closest_right_idx == - 1 ) {
closest_right_idx = found_higher_idx ;
} else if ( pts [ found_higher_idx ][ 0 ] < pts [ closest_right_idx ][ 0 ]) {
closest_right_idx = found_higher_idx ;
}
}
// NOTE else?
bound_x_sorted_idx = node -> left_x_cascading_map [ bound_x_sorted_idx ];
node = node -> left ;
} else {
bound_x_sorted_idx = node -> right_x_cascading_map [ bound_x_sorted_idx ];
node = node -> right ;
}
}
// NOTE
// if(closest_right_idx == -1){
// }
return closest_right_idx ;
}
int QueryLeft ( int qx , int qy ) const {
Node * node = root ;
int bound_x_sorted_idx = UpperBound ( x_sorted_idx , qx ) - 1 ;
int closest_left_idx = - 1 ;
while ( node -> left != nullptr && node -> right != nullptr ) {
// std::cout << "----------------" << std::endl;
// std::cout << "y med: " << node->y_med << std::endl;
// std::cout << "lower_bound idx: " << bound_x_sorted_idx << std::endl;
// std::cout << "x_sorted_idx : \n\t";
// for (const auto& idx : node->x_sorted_idx) {
// std::cout << idx << " ";
// }
// std::cout << std::endl;
// std::cout << "left_cascading_map_inverse : \n\t";
// for (const auto& cascading_idx : node->left_x_cascading_map_inverse) {
// std::cout << cascading_idx << " ";
// }
// std::cout << std::endl;
// std::cout << "left->x_sorted_idx : \n\t";
// for (const auto& idx : node->left->x_sorted_idx) {
// std::cout << idx << " ";
// }
// std::cout << std::endl;
// std::cout << "right_cascading_map_inverse : \n\t";
// for (const auto& cascading_idx : node->right_x_cascading_map_inverse) {
// std::cout << cascading_idx << " ";
// }
// std::cout << std::endl;
// std::cout << "right->x_sorted_idx : \n\t";
// for (const auto& idx : node->right->x_sorted_idx) {
// std::cout << idx << " ";
// }
// std::cout << std::endl;
// std::cout << "left 1, right 0 : " << (qy <= node->y_med) << std::endl;
// std::cout << "closest_left_idx : " << closest_left_idx << std::endl;
if ( bound_x_sorted_idx < 0 ) {
break ;
}
// NOTE
// qy 랑 같은 y 에 멈출지 말지? (output sensitive 관련)
if ( qy < node -> y_med ) {
int found_higher_x_sorted_idx =
node -> right_x_cascading_map_inverse [ bound_x_sorted_idx ];
if ( found_higher_x_sorted_idx >= 0 ) {
int found_higher_idx =
node -> right -> x_sorted_idx [ found_higher_x_sorted_idx ];
if ( closest_left_idx == - 1 ) {
closest_left_idx = found_higher_idx ;
} else if ( pts [ found_higher_idx ][ 0 ] > pts [ closest_left_idx ][ 0 ]) {
closest_left_idx = found_higher_idx ;
}
}
// NOTE else?
bound_x_sorted_idx =
node -> left_x_cascading_map_inverse [ bound_x_sorted_idx ];
node = node -> left ;
} else {
bound_x_sorted_idx =
node -> right_x_cascading_map_inverse [ bound_x_sorted_idx ];
node = node -> right ;
}
}
// NOTE
// last node consideration?
if ( node -> left == nullptr && node -> right == nullptr ) {
if ( pts [ node -> x_sorted_idx [ 0 ]][ 0 ] <= qx &&
pts [ node -> x_sorted_idx [ 0 ]][ 1 ] >= qy ) {
if \ ( closest \ _left \ _idx == - 1 \ ||
pts [ node -> x_sorted_idx [ 0 ]][ 0 ] > pts [ closest_left_idx ][ 0 ]) {
closest_left_idx = node -> x_sorted_idx [ 0 ];
}
}
}
return closest_left_idx ;
}
// x_sorted_idx -> evaluation -> upperbound -> idx
int UpperBound ( const std :: vector < int >& x_sorted_idx_ , int qx ) const {
int l = 0 ;
// not containing end r
int r = x_sorted_idx_ . size ();
while ( l < r ) {
int med_idx = ( l + r ) / 2 ;
int med = pts [ x_sorted_idx_ [ med_idx ]][ 0 ];
if ( med <= qx ) {
l = med_idx + 1 ;
} else {
r = med_idx ;
}
}
return l ;
}
// x_sorted_idx -> evaluation -> lowerbound -> idx
int LowerBound ( const std :: vector < int >& x_sorted_idx_ , int qx ) const {
int l = 0 ;
// not containing end r
int r = x_sorted_idx_ . size ();
while ( l < r ) {
int med_idx = ( l + r ) / 2 ;
int med = pts [ x_sorted_idx_ [ med_idx ]][ 0 ];
if ( med < qx ) {
l = med_idx + 1 ;
} else {
r = med_idx ;
}
}
return l ;
}
};
class Solution {
public:
// using output-sensitive solution
std :: vector < std :: vector < int >> getSkyline (
std :: vector < std :: vector < int >>& buildings ) {
std :: chrono :: high_resolution_clock :: time_point begin ;
std :: chrono :: high_resolution_clock :: time_point end ;
std :: vector < std :: vector < int >> new_buildings ;
begin = std :: chrono :: high_resolution_clock :: now ();
new_buildings = PreprocessBuildings ( buildings );
end = std :: chrono :: high_resolution_clock :: now ();
std :: cout << "# preprocess : "
<< std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( end -
begin )
. count ()
<< std :: endl ;
int n = new_buildings . size ();
// starting at 4 too slow
int h_cnt = 2 ;
int h_star = 2 ;
// 2, 4, 16, 256 , ...
std :: vector < std :: vector < int >> ans ;
while ( 1 ) {
h_star = ( 1 << ( 1 << h_cnt ++ ));
std :: vector < std :: vector < int >> skyline ;
int k = n / h_star ;
if ( h_star * k < n ) {
k ++ ;
}
//
// std::cout << "----- Skyline ----- [ h*: " << h_star << ", k: " << k
// << " ]" << std::endl;
begin = std :: chrono :: high_resolution_clock :: now ();
std :: vector < std :: vector < std :: vector < int >>> subgp_buildings ( k );
for ( int i = 0 ; i < n ; i ++ ) {
int subgp_idx = i / h_star ;
subgp_buildings [ subgp_idx ]. push_back ( new_buildings [ i ]);
}
std :: vector < std :: vector < std :: vector < int >>> subgp_skylines ;
subgp_skylines . reserve ( k );
for ( int i = 0 ; i < k ; i ++ ) {
std :: chrono :: high_resolution_clock :: time_point b =
std :: chrono :: high_resolution_clock :: now ();
subgp_skylines . emplace_back ( GetSkylineSlow ( subgp_buildings [ i ]));
std :: chrono :: high_resolution_clock :: time_point e =
std :: chrono :: high_resolution_clock :: now ();
// std::cout << "# subgp each skyline : " <<
// std::chrono::duration_cast<std::chrono::milliseconds>(e - b).count()
// << std::endl; std::cout << "skyline for subgp " << i << std::endl;
// for (const auto& pt : subgp_skylines[i]) {
// std::cout << "(" << pt[0] << ", " << pt[1] << ") - ";
// }
// std::cout << std::endl;
}
if ( k == 1 ) {
return subgp_skylines [ 0 ];
}
end = std :: chrono :: high_resolution_clock :: now ();
std :: cout << "# subgp skyline [" << h_star << ", " << k << "]: "
<< std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( end -
begin )
. count ()
<< std :: endl ;
begin = std :: chrono :: high_resolution_clock :: now ();
std :: vector < Tree > subgp_trees ;
subgp_trees . reserve ( k );
int sum_td1 = 0 , sum_td2 = 0 , sum_td3 = 0 , sum_td4 = 0 , sum_td5 = 0 ,
sum_td6 = 0 ;
for ( int i = 0 ; i < k ; i ++ ) {
subgp_trees . emplace_back ( subgp_skylines [ i ]);
sum_td1 += subgp_trees . back (). td1 ;
sum_td2 += subgp_trees . back (). td2 ;
sum_td3 += subgp_trees . back (). td3 ;
sum_td4 += subgp_trees . back (). td4 ;
sum_td5 += subgp_trees . back (). td5 ;
sum_td6 += subgp_trees . back (). td6 ;
}
end = std :: chrono :: high_resolution_clock :: now ();
std :: cout << "# tree construction : "
<< std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( end -
begin )
. count ()
<< std :: endl ;
// std::cout << "# tree construction td1: " << sum_td1 << std::endl;
// std::cout << "# tree construction td2: " << sum_td2 << std::endl;
// std::cout << "# tree construction td3: " << sum_td3 << std::endl;
// std::cout << "# tree construction td4: " << sum_td4 << std::endl;
// std::cout << "# tree construction td5: " << sum_td5 << std::endl;
// std::cout << "# tree construction td6: " << sum_td6 << std::endl;
// merge
int cur_x = 0 ;
int cur_y = 0 ;
int cur_subgp_idx = - 1 ;
int cur_subgp_pt_idx = - 1 ;
bool succeeded = false ;
// from start point, h_start + 1 iteration needed
for ( int i = 0 ; i <= h_star ; i ++ ) {
begin = std :: chrono :: high_resolution_clock :: now ();
// std::cout << "- h* loop : " << i << " / " << h_star << std::endl;
// std::cout << "cur_x: " << cur_x << std::endl
// << "cur_y: " << cur_y << std::endl
// << "cur_subgp_idx: " << cur_subgp_idx << std::endl
// << "cur_subgp_pt_idx: " << cur_subgp_pt_idx << std::endl;
int next_x , next_y , next_subgp_idx , next_subgp_pt_idx ;
std :: tie ( next_x , next_y , next_subgp_idx , next_subgp_pt_idx ) =
FindNextSkylinePt ( subgp_trees , cur_x , cur_y );
// std::cout << "next_x: " << next_x << std::endl
// << "next_y: " << next_y << std::endl
// << "next_subgp_idx: " << next_subgp_idx << std::endl
// << "next_subgp_pt_idx: " << next_subgp_pt_idx << std::endl;
// std::cout
// << "Query next response: "
// << \(cur\_subgp\_idx == -1 \||
// cur_subgp_pt_idx < subgp_trees[cur_subgp_idx].pts.size() - 1)
// << \(next\_x == -1 \||
// (cur_subgp_idx != -1 &&
// next_x >
// subgp_trees[cur_subgp_idx].pts[cur_subgp_pt_idx +
// 1][0]))
// << std::endl;
if \ ( cur \ _subgp \ _idx == - 1 \ ||
cur_subgp_pt_idx < subgp_trees [ cur_subgp_idx ]. pts . size () - 1 ) {
// next subgp pt exists
if \ ( next \ _x == - 1 \ ||
( cur_subgp_idx != - 1 &&
next_x >
subgp_trees [ cur_subgp_idx ]. pts [ cur_subgp_pt_idx + 1 ][ 0 ])) {
// no query response
// if cur_subgp_idx == -1 (init), it must jump
// to be drop case, next_x must be farther than the cur next x
// drop to cur_subgp_idx+1 and need to find y
// assert idx not -1 if no query resp
int cur_next_x =
subgp_trees [ cur_subgp_idx ]. pts [ cur_subgp_pt_idx + 1 ][ 0 ];
int cur_next_y =
subgp_trees [ cur_subgp_idx ]. pts [ cur_subgp_pt_idx + 1 ][ 1 ];
int prev_x , prev_y , prev_subgp_idx , prev_subgp_pt_idx ;
// std::cout << "Query prev: (" << cur_next_x << ", " << cur_next_y
// << ")" << std::endl;
// NOTE: query y?
std :: tie ( prev_x , prev_y , prev_subgp_idx , prev_subgp_pt_idx ) =
FindPrevSkylinePt ( subgp_trees , cur_next_x , 0 , cur_subgp_idx );
// std::cout << "prev_x: " << prev_x << std::endl
// << "prev_y: " << prev_y << std::endl
// << "prev_subgp_idx: " << prev_subgp_idx << std::endl
// << "prev_subgp_pt_idx: " << prev_subgp_pt_idx
// << std::endl;
// drop to prev y only if it is higher than drop height in the same
// subgp
if ( prev_y != - 1 && prev_y > cur_next_y ) {
cur_x = cur_next_x ;
cur_y = prev_y ;
cur_subgp_idx = prev_subgp_idx ;
cur_subgp_pt_idx = prev_subgp_pt_idx ;
} else {
// drop to current subgp next pt
cur_x = cur_next_x ;
cur_y = cur_next_y ;
cur_subgp_pt_idx = cur_subgp_pt_idx + 1 ;
}
} else {
// jump (move to the query response)
// including cur subgp.
cur_x = next_x ;
cur_y = next_y ;
cur_subgp_idx = next_subgp_idx ;
cur_subgp_pt_idx = next_subgp_pt_idx ;
}
} else {
// else pt is the last (0,0) of the subgp
if ( next_x == - 1 ) {
// no query response
succeeded = true ;
break ;
} else {
// jump (move to the query response)
cur_x = next_x ;
cur_y = next_y ;
cur_subgp_idx = next_subgp_idx ;
cur_subgp_pt_idx = next_subgp_pt_idx ;
}
}
// std::cout << "-- skyline push : (" << cur_x << ", " << cur_y << ")"
// << std::endl;
skyline . push_back ({ cur_x , cur_y });
end = std :: chrono :: high_resolution_clock :: now ();
// std::cout << "# h* loop queary : " <<
// std::chrono::duration_cast<std::chrono::milliseconds>(end -
// begin).count() << std::endl;
}
if ( succeeded ) {
ans = skyline ;
break ;
} else {
; // std::cout << " - fail" << std::endl;
}
// h_star = h_star * h_star;
}
return ans ;
}
std :: tuple < int , int , int , int > FindNextSkylinePt (
const std :: vector < Tree >& subgp_trees , int qx , int qy ) const {
int next_x = - 1 ;
int next_y = - 1 ;
int next_subgp_idx = - 1 ;
int next_subgp_pt_idx = - 1 ;
for ( int j = 0 ; j < subgp_trees . size (); j ++ ) {
const auto & subgp_tree = subgp_trees [ j ];
int resp_idx = subgp_tree . QueryRight ( qx , qy );
if ( resp_idx > subgp_tree . pts . size ()) {
continue ;
}
int next_cand_x = subgp_tree . pts [ resp_idx ][ 0 ];
int next_cand_y = subgp_tree . pts [ resp_idx ][ 1 ];
if \ ( next \ _x == - 1 \ || std :: pair < int , int > \ ( next \ _x , - next \ _y ) >
std :: pair < int , int > ( next_cand_x , - next_cand_y )) {
next_x = next_cand_x ;
next_y = next_cand_y ;
next_subgp_idx = j ;
next_subgp_pt_idx = resp_idx ;
}
}
return std :: make_tuple ( next_x , next_y , next_subgp_idx , next_subgp_pt_idx );
}
// regardless x , find highest y value dominating query pt
// return highest except cur subgp
std :: tuple < int , int , int , int > FindPrevSkylinePt (
const std :: vector < Tree >& subgp_trees , int qx , int qy ,
int cur_subgp_idx ) const {
int prev_x = - 1 ;
int prev_y = - 1 ;
int prev_subgp_idx = - 1 ;
int prev_subgp_pt_idx = - 1 ;
for ( int j = 0 ; j < subgp_trees . size (); j ++ ) {
if ( j == cur_subgp_idx ) {
continue ;
}
const auto & subgp_tree = subgp_trees [ j ];
int resp_idx = subgp_tree . QueryLeft ( qx , qy );
if ( resp_idx > subgp_tree . pts . size ()) {
continue ;
}
int prev_cand_x = subgp_tree . pts [ resp_idx ][ 0 ];
int prev_cand_y = subgp_tree . pts [ resp_idx ][ 1 ];
if \ ( prev \ _x == - 1 \ || prev \ _y < prev \ _cand \ _y ) {
prev_x = prev_cand_x ;
prev_y = prev_cand_y ;
prev_subgp_idx = j ;
prev_subgp_pt_idx = resp_idx ;
}
}
return std :: make_tuple ( prev_x , prev_y , prev_subgp_idx , prev_subgp_pt_idx );
}
// find skyline given building segments in O(n log n)
std :: vector < std :: vector < int >> GetSkylineSlow (
std :: vector < std :: vector < int >>& buildings ) {
std :: vector < std :: vector < int >> skyline ;
skyline . reserve ( buildings . size () * 2 );
std :: vector < std :: pair < int , int >> segs ;
segs . reserve ( buildings . size ());
for ( int i = 0 ; i < buildings . size (); i ++ ) {
const auto & b = buildings [ i ];
segs . push_back ({ b [ 0 ], i });
segs . push_back ({ b [ 1 ], i });
}
std :: sort ( segs . begin (), segs . end ());
std :: priority_queue < std :: pair < int , int >> pq ;
int seg_idx = 0 ;
while ( seg_idx < segs . size ()) {
int cur_x ;
std :: tie ( cur_x , std :: ignore ) = segs [ seg_idx ];
while ( seg_idx < segs . size () && cur_x == segs [ seg_idx ]. first ) {
int building_idx ;
std :: tie ( std :: ignore , building_idx ) = segs [ seg_idx ];
const auto & b = buildings [ building_idx ];
if ( b [ 0 ] == cur_x ) {
pq . push ({ b [ 2 ], b [ 1 ]});
// pq.emplace(b[2], b[1]);
}
seg_idx ++ ;
}
// remove immediately as it ends
while ( ! pq . empty () && pq . top (). second <= cur_x ) {
pq . pop ();
}
int cur_height = 0 ;
if ( ! pq . empty ()) {
cur_height = pq . top (). first ;
}
if \ ( skyline . empty \ () \ || skyline . back \ () \ [ 1 ] != cur \ _height ) {
skyline . push_back ({ cur_x , cur_height });
}
}
return skyline ;
}
// remove same height connected buildings
std :: vector < std :: vector < int >> PreprocessBuildings (
std :: vector < std :: vector < int >>& buildings ) {
std :: unordered_map < int , int > um ;
std :: vector < std :: vector < int >> new_buildings ;
new_buildings . reserve ( buildings . size ());
int idx = 0 ;
for ( const auto & b : buildings ) {
if ( um . find ( b [ 2 ]) == um . end ()) {
new_buildings . push_back ( b );
um [ b [ 2 ]] = idx ++ ;
} else {
// assert um[b[2]] not empty
auto & last_b = new_buildings [ um [ b [ 2 ]]];
// intersects
if ( last_b [ 1 ] >= b [ 0 ]) {
if ( last_b [ 1 ] < b [ 1 ]) {
last_b [ 1 ] = b [ 1 ];
}
// contained
} else {
// separated
new_buildings . push_back ( b );
um [ b [ 2 ]] = idx ++ ;
}
}
}
return new_buildings ;
}
void TestTree () {
std :: cout << "===== TestTree =====" << std :: endl ;
std :: vector < std :: vector < int >> pts = {
{ 2 , 10 }, { 3 , 15 }, { 5 , 12 }, { 15 , 10 }, { 19 , 8 }};
Tree t ( pts );
}
void TestQuery () {
std :: cout << "===== TestQuery =====" << std :: endl ;
std :: vector < std :: vector < int >> pts = {
{ 10 , 10 }, { 8 , 15 }, { 6 , 12 }, { 6 , 10 },
{ 6 , 8 }, { 4 , 8 }, { 2 , 8 }};
Tree t ( pts );
std :: vector < int > test_list = { 6 , 5 , 4 , 3 , 2 , 1 , 0 };
int i ;
i = t . LowerBound ( test_list , 5 );
std :: cout << "test lowerbound for 5 : " << i << std :: endl ;
i = t . LowerBound ( test_list , 6 );
std :: cout << "test lowerbound for 6 : " << i << std :: endl ;
i = t . LowerBound ( test_list , 7 );
std :: cout << "test lowerbound for 7 : " << i << std :: endl ;
i = t . LowerBound ( test_list , 0 );
std :: cout << "test lowerbound for 0 : " << i << std :: endl ;
i = t . LowerBound ( test_list , 11 );
std :: cout << "test lowerbound for 11 : " << i << std :: endl ;
i = t . UpperBound ( test_list , 5 );
std :: cout << "test upperbound for 5 : " << i << std :: endl ;
i = t . UpperBound ( test_list , 6 );
std :: cout << "test upperbound for 6 : " << i << std :: endl ;
i = t . UpperBound ( test_list , 7 );
std :: cout << "test upperbound for 7 : " << i << std :: endl ;
i = t . UpperBound ( test_list , 0 );
std :: cout << "test upperbound for 0 : " << i << std :: endl ;
i = t . UpperBound ( test_list , 11 );
std :: cout << "test upperbound for 11 : " << i << std :: endl ;
}
void TestQuery2 () {
std :: cout << "===== TestQuery2 =====" << std :: endl ;
std :: vector < std :: vector < int >> pts = {
{ 2 , 14 }, { 4 , 26 }, { 6 , 8 }, { 8 , 4 }, { 10 , 12 }, { 12 , 6 }, { 14 , 20 },
{ 16 , 10 }, { 18 , 2 }, { 20 , 18 }, { 22 , 24 }, { 24 , 16 }, { 26 , 22 }, { 28 , 28 }};
Tree t ( pts );
std :: cout << "pts : " << std :: endl ;
for ( const auto & pt : pts ) {
std :: cout << "(" << pt [ 0 ] << ", " << pt [ 1 ] << ") - " ;
}
std :: cout << std :: endl ;
std :: cout << "y_order : " << std :: endl ;
for ( const auto & idx : t . x_sorted_idx ) {
std :: cout << t . idx_to_y_order [ idx ] << " " ;
}
std :: cout << std :: endl ;
std :: vector < std :: vector < int >> qs = {
{ 9 , 5 }, { 9 , 13 }, { 11 , 5 }, { 11 , 13 },
{ 9 , 27 }, { 9 , 28 }, { 29 , 1 }, { 28 , 1 },
{ 0 , 14 }, { 0 , 15 }, { 15 , 1 }, { 19 , 18 }};
for ( int i = 0 ; i < qs . size (); i ++ ) {
std :: cout << "Query : (" << qs [ i ][ 0 ] << ", " << qs [ i ][ 1 ]
<< ") : " << std :: endl ;
int qidx = t . QueryRight ( qs [ i ][ 0 ], qs [ i ][ 1 ]);
if ( qidx != - 1 ) {
std :: cout << qidx << " => "
<< "(" << pts [ qidx ][ 0 ] << ", " << pts [ qidx ][ 1 ] << ")"
<< std :: endl ;
} else {
std :: cout << qidx << " => not found" << std :: endl ;
}
}
}
void TestQuery3 () {
std :: cout << "===== TestQuery3 =====" << std :: endl ;
std :: vector < std :: vector < int >> pts = {
{ 2 , 14 }, { 4 , 26 }, { 6 , 8 }, { 8 , 4 },
{ 10 , 12 }, { 12 , 6 }, { 14 , 20 }, { 16 , 10 },
{ 18 , 2 }, { 20 , 18 }, { 22 , 24 }, { 24 , 16 },
{ 26 , 22 }, { 28 , 28 }, { 30 , 0 }};
Tree t ( pts );
std :: cout << "pts : " << std :: endl ;
for ( const auto & pt : pts ) {
std :: cout << "(" << pt [ 0 ] << ", " << pt [ 1 ] << ") - " ;
}
std :: cout << std :: endl ;
std :: cout << "y_order : " << std :: endl ;
for ( const auto & idx : t . x_sorted_idx ) {
std :: cout << t . idx_to_y_order [ idx ] << " " ;
}
std :: cout << std :: endl ;
std :: vector < std :: vector < int >> qs = {
{ 9 , 5 }, { 9 , 13 }, { 11 , 5 }, { 11 , 13 },
{ 9 , 27 }, { 9 , 28 }, { 29 , 1 }, { 28 , 1 },
{ 0 , 14 }, { 0 , 15 }, { 15 , 1 }, { 19 , 18 },
{ 28 , 28 }, { 2 , 14 }, { 26 , 22 }, { 31 , 0 }};
for ( int i = 0 ; i < qs . size (); i ++ ) {
std :: cout << "Query : (" << qs [ i ][ 0 ] << ", " << qs [ i ][ 1 ]
<< ") : " << std :: endl ;
int qidx = t . QueryLeft ( qs [ i ][ 0 ], qs [ i ][ 1 ]);
if ( qidx != - 1 ) {
std :: cout << qidx << " => "
<< "(" << pts [ qidx ][ 0 ] << ", " << pts [ qidx ][ 1 ] << ")"
<< std :: endl ;
} else {
std :: cout << qidx << " => not found" << std :: endl ;
}
}
}
void TestSlow () {
std :: cout << "===== TestSlow =====" << std :: endl ;
std :: vector < std :: vector < int >> buildings = {
{ 2 , 9 , 10 }, { 3 , 7 , 15 }, { 5 , 12 , 12 }, { 15 , 20 , 10 }, { 19 , 24 , 8 }};
std :: vector < std :: vector < int >> ans ;
ans = GetSkylineSlow ( buildings );
for ( const auto & pt : ans ) {
std :: cout << "(" << pt [ 0 ] << ", " << pt [ 1 ] << ") - " ;
}
std :: cout << std :: endl ;
}
void TestSlow2 () {
std :: cout << "===== TestSlow2 =====" << std :: endl ;
std :: vector < std :: vector < int >> buildings ;
int n = 10 ;
for ( int i = 1 ; i <= n ; i ++ ) {
buildings . push_back ({ i , 2 * n - i + 1 , i });
}
std :: vector < std :: vector < int >> ans ;
ans = GetSkylineSlow ( buildings );
for ( const auto & pt : ans ) {
std :: cout << "(" << pt [ 0 ] << ", " << pt [ 1 ] << ") - " ;
}
std :: cout << std :: endl ;
}
void TestSlow3 () {
std :: cout << "===== TestSlow3 =====" << std :: endl ;
std :: vector < std :: vector < int >> buildings ;
int n = 30 ;
for ( int i = 1 ; i <= n ; i ++ ) {
if ( i % 3 != 0 ) {
buildings . push_back ({ i , i + 1 , 2 });
}
}
std :: vector < std :: vector < int >> ans ;
ans = GetSkylineSlow ( buildings );
for ( const auto & pt : ans ) {
std :: cout << "(" << pt [ 0 ] << ", " << pt [ 1 ] << ") - " ;
}
std :: cout << std :: endl ;
}
void TestSkyline () {
std :: cout << "===== TestSkyline =====" << std :: endl ;
std :: vector < std :: vector < int >> buildings = {
{ 2 , 9 , 10 }, { 3 , 7 , 15 }, { 5 , 12 , 12 }, { 15 , 20 , 10 }, { 19 , 24 , 8 }};
std :: vector < std :: vector < int >> ans ;
ans = getSkyline ( buildings );
for ( const auto & pt : ans ) {
std :: cout << "(" << pt [ 0 ] << ", " << pt [ 1 ] << ") - " ;
}
std :: cout << std :: endl ;
}
void TestSkyline2 () {
std :: cout << "===== TestSkyline2 =====" << std :: endl ;
std :: vector < std :: vector < int >> buildings ;
int n = 100 ;
for ( int i = 1 ; i <= n ; i ++ ) {
buildings . push_back ({ i + 1 , 2 * n - i + 2 , i });
}
buildings . push_back ({ 1 , 202 , 101 });
std :: vector < std :: vector < int >> ans ;
ans = getSkyline ( buildings );
std :: cout << "----- Result -----" << std :: endl ;
for ( const auto & pt : ans ) {
std :: cout << "(" << pt [ 0 ] << ", " << pt [ 1 ] << ") - " ;
}
std :: cout << std :: endl ;
}
void TestSkyline3 () {
std :: cout << "===== TestSkyline3 =====" << std :: endl ;
std :: vector < std :: vector < int >> buildings ;
int n = 30 ;
for ( int i = 1 ; i <= n ; i ++ ) {
if ( i % 3 != 0 ) {
buildings . push_back ({ i , i + 1 , 2 });
}
}
std :: vector < std :: vector < int >> ans ;
ans = getSkyline ( buildings );
std :: cout << "----- Result -----" << std :: endl ;
for ( const auto & pt : ans ) {
std :: cout << "(" << pt [ 0 ] << ", " << pt [ 1 ] << ") - " ;
}
std :: cout << std :: endl ;
}
void TestSkyline4 () {
std :: cout << "===== TestSkyline4 =====" << std :: endl ;
std :: vector < std :: vector < int >> buildings = {
{ 1 , 2 , 1 }, { 1 , 2 , 2 }, { 1 , 2 , 3 },
{ 2 , 3 , 1 }, { 2 , 3 , 2 }, { 2 , 3 , 3 }};
std :: vector < std :: vector < int >> ans ;
ans = getSkyline ( buildings );
std :: cout << "----- Result -----" << std :: endl ;
for ( const auto & pt : ans ) {
std :: cout << "(" << pt [ 0 ] << ", " << pt [ 1 ] << ") - " ;
}
std :: cout << std :: endl ;
}
void TestSkyline5 () {
std :: cout << "===== TestSkyline5 =====" << std :: endl ;
std :: vector < std :: vector < int >> buildings = {
{ 1 , 38 , 219 }, { 2 , 19 , 228 }, { 2 , 64 , 106 }, { 3 , 80 , 65 },
{ 3 , 84 , 8 }, { 4 , 12 , 8 }, { 4 , 25 , 14 }, { 4 , 46 , 225 },
{ 4 , 67 , 187 }, { 5 , 36 , 118 }, { 5 , 48 , 211 }, { 5 , 55 , 97 },
{ 6 , 42 , 92 }, { 6 , 56 , 188 }, { 7 , 37 , 42 }, { 7 , 49 , 78 },
{ 7 , 84 , 163 }, { 8 , 44 , 212 }, { 9 , 42 , 125 }, { 9 , 85 , 200 },
{ 9 , 100 , 74 }, { 10 , 13 , 58 }, { 11 , 30 , 179 }, { 12 , 32 , 215 },
{ 12 , 33 , 161 }, { 12 , 61 , 198 }, { 13 , 38 , 48 }, { 13 , 65 , 222 },
{ 14 , 22 , 1 }, { 15 , 70 , 222 }, { 16 , 19 , 196 }, { 16 , 24 , 142 },
{ 16 , 25 , 176 }, { 16 , 57 , 114 }, { 18 , 45 , 1 }, { 19 , 79 , 149 },
{ 20 , 33 , 53 }, { 21 , 29 , 41 }, { 23 , 77 , 43 }, { 24 , 41 , 75 },
{ 24 , 94 , 20 }, { 27 , 63 , 2 }, { 31 , 69 , 58 }, { 31 , 88 , 123 },
{ 31 , 88 , 146 }, { 33 , 61 , 27 }, { 35 , 62 , 190 }, { 35 , 81 , 116 },
{ 37 , 97 , 81 }, { 38 , 78 , 99 }, { 39 , 51 , 125 }, { 39 , 98 , 144 },
{ 40 , 95 , 4 }, { 45 , 89 , 229 }, { 47 , 49 , 10 }, { 47 , 99 , 152 },
{ 48 , 67 , 69 }, { 48 , 72 , 1 }, { 49 , 73 , 204 }, { 49 , 77 , 117 },
{ 50 , 61 , 174 }, { 50 , 76 , 147 }, { 52 , 64 , 4 }, { 52 , 89 , 84 },
{ 54 , 70 , 201 }, { 57 , 76 , 47 }, { 58 , 61 , 215 }, { 58 , 98 , 57 },
{ 61 , 95 , 190 }, { 66 , 71 , 34 }, { 66 , 99 , 53 }, { 67 , 74 , 9 },
{ 68 , 97 , 175 }, { 70 , 88 , 131 }, { 74 , 77 , 155 }, { 74 , 99 , 145 },
{ 76 , 88 , 26 }, { 82 , 87 , 40 }, { 83 , 84 , 132 }, { 88 , 99 , 99 }};
std :: vector < std :: vector < int >> ans ;
ans = getSkyline ( buildings );
std :: cout << "----- Result -----" << std :: endl ;
for ( const auto & pt : ans ) {
std :: cout << "[" << pt [ 0 ] << ", " << pt [ 1 ] << "], " ;
}
std :: cout << std :: endl ;
}
void TestSkyline6 () {
std :: cout << "===== TestSkyline6 =====" << std :: endl ;
std :: ifstream infile ( "test_input" );
std :: vector < std :: vector < int >> buildings ;
int x1 , x2 , y ;
while ( ! infile . eof ()) {
infile >> x1 >> x2 >> y ;
buildings . push_back ({ x1 , x2 , y });
}
std :: cout << "input length: " << buildings . size () << std :: endl ;
std :: vector < std :: vector < int >> ans ;
ans = getSkyline ( buildings );
std :: cout << "----- Result -----" << std :: endl ;
for ( const auto & pt : ans ) {
std :: cout << "[" << pt [ 0 ] << ", " << pt [ 1 ] << "], " ;
}
std :: cout << std :: endl ;
}
std :: vector < std :: vector < int >> GenerateRandomInput ( int n , std :: mt19937 & gen ) {
std :: uniform_int_distribution < int > dist_x ( 1 , 1 << 20 );
std :: uniform_int_distribution < int > dist_y ( 1 , 1 << 20 );
std :: vector < std :: vector < int >> buildings ( n );
for ( int i = 0 ; i < n ; i ++ ) {
int x1 , x2 , y ;
x1 = dist_x ( gen );
x2 = dist_x ( gen );
y = dist_y ( gen );
if ( x1 > x2 ) {
int tmp = x1 ;
x1 = x2 ;
x2 = tmp ;
} else if ( x1 == x2 ) {
x2 = x1 + 1 ;
}
buildings [ i ] = { x1 , x2 , y };
}
std :: sort ( buildings . begin (), buildings . end ());
return buildings ;
}
void ProfileTC () {
int repetition = 2 ;
std :: random_device rd ;
std :: mt19937 gen ( 1234 ); // rd()
std :: stringstream ss ;
std :: ofstream outfile ( "profile" );
int scale = 20000000 ;
for ( int n = scale ; n <= scale * 1 ; n = n + scale / 2 ) {
for ( int i = 0 ; i < repetition ; i ++ ) {
std :: vector < std :: vector < int >> buildings = GenerateRandomInput ( n , gen );
std :: chrono :: high_resolution_clock :: time_point begin ;
std :: chrono :: high_resolution_clock :: time_point end ;
std :: vector < std :: vector < int >> ans ;
begin = std :: chrono :: high_resolution_clock :: now ();
ans = GetSkylineSlow ( buildings );
end = std :: chrono :: high_resolution_clock :: now ();
int h1 = ans . size ();
auto time_ms1 =
std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( end - begin )
. count ();
begin = std :: chrono :: high_resolution_clock :: now ();
ans = getSkyline ( buildings );
end = std :: chrono :: high_resolution_clock :: now ();
int h2 = ans . size ();
auto time_ms2 =
std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( end - begin )
. count ();
int h = - 1 ;
if ( h1 == h2 ) {
h = h1 ;
} else {
outfile << "----- Error ----- : " << h1 << " vs " << h2 << std :: endl ;
for ( const auto & b : buildings ) {
outfile << b [ 0 ] << " " << b [ 1 ] << " " << b [ 2 ] << std :: endl ;
}
return ;
}
outfile << n << " " << h << " " << time_ms1 << " " << time_ms2
<< std :: endl ;
}
}
// outfile << ss.rdbuf();
}
};
int main () {
Solution s ;
// s.TestTree();
// s.TestQuery();
// s.TestQuery2();
// s.TestQuery3();
// s.TestSlow();
// s.TestSlow2();
// s.TestSlow3();
// s.TestSkyline();
// s.TestSkyline2();
// s.TestSkyline3();
// s.TestSkyline4();
// s.TestSkyline5();
// s.TestSkyline6();
s . ProfileTC ();
return 0 ;
}