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

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <queue>
#include <vector>

#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

const double EPS = 1e-7;

template <class T> struct point {
  T x, y;
  point operator+(const point &a) const { return (point){x + a.x, y + a.y}; }
  point operator-(const point &a) const { return (point){x - a.x, y - a.y}; }
};

template <class T> point<T> operator*(T c, const point<T> &a) {
  return (point<T>){c * a.x, c * a.y};
}

bool operator<(const point<double> &a, const point<double> &b) {
  return a.x + EPS < b.x || abs(a.x - b.x) < EPS && a.y + EPS < b.y;
}
bool operator==(const point<double> &a, const point<double> &b) {
  return abs(a.x - b.x) < EPS && abs(a.y - b.y) < EPS;
}

template <class T> T dot(const point<T> &a, const point<T> &b) {
  return a.x * b.x + a.y * b.y;
}

template <class T> T cross(const point<T> &a, const point<T> &b) {
  return a.x * b.y - a.y * b.x;
}

template <class T> double abs(const point<T> &a) {
  return sqrt(a.x * a.x + a.y * a.y);
}

template <class T> struct segment {
  point<T> a, b;
};

enum { CCW = 1, CW = -1, ON = 0 };
int ccw(const point<double> &a, const point<double> &b,
        const point<double> &c) {
  double rdir = cross(b - a, c - a);
  if (rdir > EPS)
    return CCW;
  if (rdir < -EPS)
    return CW;
  return ON;
}

template <class T> double dist(const point<T> &a, const point<T> &b) {
  return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

bool cover(const segment<double> &S, const point<double> &p) {
  return abs(cross(S.a - p, S.b - p)) < EPS && dot(S.a - p, S.b - p) < EPS;
}

bool intersect(const segment<double> &S1, const segment<double> &S2) {
  if (max(S1.a.x, S1.b.x) + EPS < min(S2.a.x, S2.b.x) ||
      max(S1.a.y, S1.b.y) + EPS < min(S2.a.y, S2.b.y) ||
      max(S2.a.x, S2.b.x) + EPS < min(S1.a.x, S1.b.x) ||
      max(S2.a.y, S2.b.y) + EPS < min(S1.a.y, S1.b.y))
    return false;
  return ccw(S1.a, S1.b, S2.a) * ccw(S1.a, S1.b, S2.b) <= 0 &&
         ccw(S2.a, S2.b, S1.a) * ccw(S2.a, S2.b, S1.b) <= 0;
}

point<double> get_intersect(const segment<double> &S1,
                            const segment<double> &S2) {
  double a1 = cross(S1.b - S1.a, S2.b - S2.a);
  double a2 = cross(S1.b - S1.a, S1.b - S2.a);
  if (abs(a1) < EPS) {
    if (cover(S1, S2.a))
      return S2.a;
    if (cover(S1, S2.b))
      return S2.b;
    if (cover(S2, S1.a))
      return S1.a;
    return S1.b;
  }
  return S2.a + a2 / a1 * (S2.b - S2.a);
}

// 追加で頂点集合を指定できるように書き換え
void arrangement(const vector<segment<double>> &S,
                 const vector<point<double>> &plus, vector<point<double>> &P,
                 vector<int> *G) {
  int n = S.size();
  P = plus;
  rep(i, n) {
    P.push_back(S[i].a);
    P.push_back(S[i].b);
    rep(j, i) if (intersect(S[i], S[j])) P.push_back(get_intersect(S[i], S[j]));
  }
  sort(P.begin(), P.end());
  P.erase(unique(P.begin(), P.end()), P.end());

  rep(i, n) {
    vector<int> on;
    rep(u, P.size()) if (cover(S[i], P[u])) on.push_back(u);
    rep(j, (int)on.size() - 1) {
      int u = on[j], v = on[j + 1];
      G[u].push_back(v);
      G[v].push_back(u);
    }
  }
}

int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  vector<segment<double>> pipe(n);
  rep(i, n) scanf("%lf%lf%lf%lf", &pipe[i].a.x, &pipe[i].a.y, &pipe[i].b.x,
                  &pipe[i].b.y);
  vector<point<double>> stop(m);
  rep(i, m) scanf("%lf%lf", &stop[i].x, &stop[i].y);
  point<double> s, t;
  scanf("%lf%lf%lf%lf", &s.x, &s.y, &t.x, &t.y);

  // 追加の頂点集合
  vector<point<double>> plus = stop;
  plus.push_back(s);
  plus.push_back(t);

  vector<point<double>> P;
  static vector<int> G[100000];
  arrangement(pipe, plus, P, G);

  int N = P.size();
  static bool isstop[100000];
  rep(i, m) rep(u, N) if (P[u] == stop[i]) isstop[u] = true;

  int s_id = find(P.begin(), P.end(), s) - P.begin();
  int t_id = find(P.begin(), P.end(), t) - P.begin();

  // t から stop をまたがずに行ける場所を見つける
  static bool vis[100000];
  vis[t_id] = true;
  queue<int> Q;
  Q.push(t_id);
  while (!Q.empty()) {
    int u = Q.front();
    Q.pop();
    rep(i, G[u].size()) {
      int v = G[u][i];
      if (!vis[v]) {
        vis[v] = true;
        if (!isstop[v])
          Q.push(v);
      }
    }
  }

  if (vis[s_id]) {
    puts("-1");
    return 0;
  }

  double ans = 0;
  rep(i, n) ans += dist(pipe[i].a, pipe[i].b);

  // s から vis を通らずに行ける場所を見つける
  static bool vis2[100000];
  vis2[s_id] = true;
  Q.push(s_id);
  while (!Q.empty()) {
    int u = Q.front();
    Q.pop();
    rep(i, G[u].size()) {
      int v = G[u][i];
      if (!vis2[v]) {
        vis2[v] = true;
        if (!vis[v])
          Q.push(v);
      }
      if (vis[v])
        ans -= dist(P[u], P[v]); // 一回カウントされる
      else
        ans -= dist(P[u], P[v]) / 2; // 二回カウントされる
    }
  }
  printf("%.9f\\n", ans);

  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <queue>
#include <vector>

#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

const double EPS = 1e-6;

template <class T> struct point {
  T x, y;
  point operator+(const point &a) const { return (point){x + a.x, y + a.y}; }
  point operator-(const point &a) const { return (point){x - a.x, y - a.y}; }
};

template <class T> point<T> operator*(T c, const point<T> &a) {
  return (point<T>){c * a.x, c * a.y};
}

bool operator<(const point<double> &a, const point<double> &b) {
  return a.x + EPS < b.x || abs(a.x - b.x) < EPS && a.y + EPS < b.y;
}
bool operator==(const point<double> &a, const point<double> &b) {
  return abs(a.x - b.x) < EPS && abs(a.y - b.y) < EPS;
}

template <class T> T dot(const point<T> &a, const point<T> &b) {
  return a.x * b.x + a.y * b.y;
}

template <class T> T cross(const point<T> &a, const point<T> &b) {
  return a.x * b.y - a.y * b.x;
}

template <class T> double abs(const point<T> &a) {
  return sqrt(a.x * a.x + a.y * a.y);
}

template <class T> struct line {
  point<T> a, b;
};

template <class T> struct segment {
  point<T> a, b;
  operator line<T>() const { return (line<T>){a, b}; }
};

enum { CCW = 1, CW = -1, ON = 0 };
int ccw(const point<double> &a, const point<double> &b,
        const point<double> &c) {
  double rdir = cross(b - a, c - a);
  if (rdir > EPS)
    return CCW;
  if (rdir < -EPS)
    return CW;
  return ON;
}

template <class T> double dist(const point<T> &a, const point<T> &b) {
  return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

bool cover(const segment<double> &S, const point<double> &p) {
  return dist(S.a, p) + dist(p, S.b) < dist(S.a, S.b) + EPS;
}

bool intersect(const segment<double> &S1, const segment<double> &S2) {
  if (max(S1.a.x, S1.b.x) + EPS < min(S2.a.x, S2.b.x) ||
      max(S1.a.y, S1.b.y) + EPS < min(S2.a.y, S2.b.y) ||
      max(S2.a.x, S2.b.x) + EPS < min(S1.a.x, S1.b.x) ||
      max(S2.a.y, S2.b.y) + EPS < min(S1.a.y, S1.b.y))
    return false;
  return ccw(S1.a, S1.b, S2.a) * ccw(S1.a, S1.b, S2.b) <= 0 &&
         ccw(S2.a, S2.b, S1.a) * ccw(S2.a, S2.b, S1.b) <= 0;
}

point<double> get_intersect(const line<double> &L1, const line<double> &L2) {
  double a1 = cross(L1.b - L1.a, L2.b - L2.a);
  double a2 = cross(L1.b - L1.a, L1.b - L2.a);
  if (abs(a1) < EPS)
    return L1.a;
  return L2.a + a2 / a1 * (L2.b - L2.a);
}

// 追加で頂点集合を指定できるように書き換え
void arrangement(const vector<segment<double>> &S,
                 const vector<point<double>> &plus, vector<point<double>> &P,
                 vector<int> *G) {
  int n = S.size();
  P = plus;
  rep(i, n) {
    P.push_back(S[i].a);
    P.push_back(S[i].b);
    rep(j, i) if (intersect(S[i], S[j])) P.push_back(get_intersect(S[i], S[j]));
  }
  sort(P.begin(), P.end());
  P.erase(unique(P.begin(), P.end()), P.end());
  if (P.size() > 10000)
    for (;;)
      ;

  rep(i, n) {
    vector<int> on;
    rep(u, P.size()) if (cover(S[i], P[u])) on.push_back(u);
    rep(j, (int)on.size() - 1) {
      int u = on[j], v = on[j + 1];
      G[u].push_back(v);
      G[v].push_back(u);
    }
  }
}

int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  vector<segment<double>> pipe(n);
  rep(i, n) scanf("%lf%lf%lf%lf", &pipe[i].a.x, &pipe[i].a.y, &pipe[i].b.x,
                  &pipe[i].b.y);
  vector<point<double>> stop(m);
  rep(i, m) scanf("%lf%lf", &stop[i].x, &stop[i].y);
  point<double> s, t;
  scanf("%lf%lf%lf%lf", &s.x, &s.y, &t.x, &t.y);

  // 追加の頂点集合
  vector<point<double>> plus = stop;
  plus.push_back(s);
  plus.push_back(t);

  vector<point<double>> P;
  vector<int> G[2000];
  arrangement(pipe, plus, P, G);

  int N = P.size();
  bool isstop[2000] = {};
  rep(i, m) rep(j, N) if (P[j] == stop[i]) isstop[j] = true;

  int s_id = find(P.begin(), P.end(), s) - P.begin();
  int t_id = find(P.begin(), P.end(), t) - P.begin();

  // t から stop をまたがずに行ける場所を見つける
  bool vis[2000] = {};
  vis[t_id] = true;
  queue<int> Q;
  Q.push(t_id);
  while (!Q.empty()) {
    int u = Q.front();
    Q.pop();
    rep(i, G[u].size()) {
      int v = G[u][i];
      if (!vis[v]) {
        vis[v] = true;
        if (!isstop[v])
          Q.push(v);
      }
    }
  }

  if (vis[s_id]) {
    puts("-1");
    return 0;
  }

  // s から vis を通らずに行ける場所を見つける
  bool vis2[2000] = {};
  vis2[s_id] = true;
  Q.push(s_id);
  while (!Q.empty()) {
    int u = Q.front();
    Q.pop();
    rep(i, G[u].size()) {
      int v = G[u][i];
      if (!vis2[v]) {
        vis2[v] = true;
        if (!vis[v])
          Q.push(v);
      }
    }
  }

  double ans = 0;
  rep(i, n) ans += dist(pipe[i].a, pipe[i].b);
  rep(u, N) rep(i, G[u].size()) {
    int v = G[u][i];
    if (u < v && vis2[u] && vis2[v])
      ans -= dist(P[u], P[v]);
  }
  printf("%.9f\\n", ans);

  return 0;
}