Problem p01180 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

struct Info {
  bool operator<(const struct Info &arg) const {
    if (x != arg.x) {
      return x < arg.x;
    } else {
      return y < arg.y;
    }
  }
  double x, y, r;
};

int N;
Info info[100001];

bool compare_y(Info left, Info right) { // 順序付け関数

  return left.y < right.y;
}

bool is_OK(int index, double x, double dist) {
  if (info[index].x < x) { // 基準線より中心が左
    if (info[index].x + info[index].r + dist < x) {
      return false;
    }

  } else { // 基準線より中心が右
    if (info[index].x - info[index].r - dist > x) {
      return false;
    }
  }

  return true;
}

double calc_dist(int a, int b) {
  return sqrt((info[a].x - info[b].x) * (info[a].x - info[b].x) +
              (info[a].y - info[b].y) * (info[a].y - info[b].y)) -
         (info[a].r + info[b].r);
}

double calc_y_dist(int a, int b) {
  return (info[b].y - info[b].r) - (info[a].y + info[a].r);
}

double closest_pair(Info *array, int tmp_N) {
  if (tmp_N <= 1)
    return DBL_MAX;

  int mid = tmp_N / 2; // 中央のインデックス

  double x = array[mid].x; // 基準線x
  double dist =
      min(closest_pair(array, mid),
          closest_pair(array + mid,
                       tmp_N - mid)); // 集合を2分割し、再帰的に最小距離を求める
  inplace_merge(array, array + mid, array + tmp_N,
                compare_y); // 2つのソート済の範囲をマージ

  vector<int> V; // ★★再帰毎にメモリを確保(indexをpush)★★

  int left, right, m, search_left;

  for (int i = 0; i < tmp_N; i++) {
    // if(!is_OK(i,x,dist))continue;
    // //基準線より最小距離以上離れている点は無視(★異なる領域間での、新最小値を作り得ないということ★)

    // ★★Vはyの昇順に並んでいる:自分よりy座標が小さいもののみ、入っている★★

    // 2分探索で、検索範囲を定める
    /*left = 0,right = V.size()-1,m = (left+right)/2;
    search_left = 0;

    while(left <= right){
            if(calc_y_dist(V[m],i) < dist){ //y座標の差がdist未満
                    search_left = m;
                    right = m-1; //より左へ
            }else{
                    left = m+1; //より右へ
            }
            m = (left+right)/2;
    }*/

    /*for(int k = search_left; k < V.size(); k++){
            dist = min(dist,calc_dist(V[k],i));
    }*/

    for (int k = 0; k < min((int)V.size(), 2); k++) {
      dist = min(dist, calc_dist(V[V.size() - 1 - k], i));
    }

    V.push_back(i); // 可能性あり集合に、iを追加
  }
  return dist;
}

void func() {

  for (int i = 0; i < N; i++) {
    scanf("%lf %lf %lf", &info[i].r, &info[i].x, &info[i].y);
  }
  sort(info, info + N);

  printf("%.10lf\\n", closest_pair(info, N));
}

int main() {

  while (true) {
    scanf("%d", &N);
    if (N == 0)
      break;

    func();
  }

  return 0;
}


Error: TLE

Fixed submission:

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

struct Info {
  bool operator<(const struct Info &arg) const {
    if (x != arg.x) {
      return x < arg.x;
    } else {
      return y < arg.y;
    }
  }
  double x, y, r;
};

int N;
Info info[100001];

bool compare_y(Info left, Info right) { // 順序付け関数

  return left.y < right.y;
}

bool is_OK(int index, double x, double dist) {
  if (info[index].x < x) { // 基準線より中心が左
    if (info[index].x + info[index].r + dist < x) {
      return false;
    }

  } else { // 基準線より中心が右
    if (info[index].x - info[index].r - dist > x) {
      return false;
    }
  }

  return true;
}

double calc_dist(int a, int b) {
  return sqrt((info[a].x - info[b].x) * (info[a].x - info[b].x) +
              (info[a].y - info[b].y) * (info[a].y - info[b].y)) -
         (info[a].r + info[b].r);
}

double calc_y_dist(int a, int b) {
  return (info[b].y - info[b].r) - (info[a].y + info[a].r);
}

double closest_pair(Info *array, int tmp_N) {
  if (tmp_N <= 1)
    return DBL_MAX;

  int mid = tmp_N / 2; // 中央のインデックス

  double x = array[mid].x; // 基準線x
  double dist =
      min(closest_pair(array, mid),
          closest_pair(array + mid,
                       tmp_N - mid)); // 集合を2分割し、再帰的に最小距離を求める
  inplace_merge(array, array + mid, array + tmp_N,
                compare_y); // 2つのソート済の範囲をマージ

  vector<int> V; // ★★再帰毎にメモリを確保(indexをpush)★★

  int left, right, m, search_left;

  for (int i = 0; i < tmp_N; i++) {
    if (!is_OK(i, x, dist))
      continue; // 基準線より最小距離以上離れている点は無視(★異なる領域間での、新最小値を作り得ないということ★)

    // ★★Vはyの昇順に並んでいる:自分よりy座標が小さいもののみ、入っている★★

    // 2分探索で、検索範囲を定める
    left = 0, right = V.size() - 1, m = (left + right) / 2;
    search_left = 0;

    while (left <= right) {
      if (calc_y_dist(V[m], i) < dist) { // y座標の差がdist未満
        search_left = m;
        right = m - 1; // より左へ
      } else {
        left = m + 1; // より右へ
      }
      m = (left + right) / 2;
    }

    for (int k = search_left; k < V.size(); k++) {
      dist = min(dist, calc_dist(V[k], i));
    }

    V.push_back(i); // 可能性あり集合に、iを追加
  }
  return dist;
}

void func() {

  for (int i = 0; i < N; i++) {
    scanf("%lf %lf %lf", &info[i].r, &info[i].x, &info[i].y);
  }
  sort(info, info + N);

  printf("%.10lf\\n", closest_pair(info, N));
}

int main() {

  while (true) {
    scanf("%d", &N);
    if (N == 0)
      break;

    func();
  }

  return 0;
}