Problem:
Problem F:
Rabbit Jumping
There are $K$ rabbits playing on rocks floating in a river. They got tired of playing on the rocks on which they are standing currently, and they decided to move to other rocks. This seemed an easy task initially, but there are so many constraints that they got totally confused.
First of all, by one leap, they can only move to a rock within $R$ meters from the current rock. Also, they can never leap over rocks. That is, when they leap in some direction, they should land on the nearest rock in that direction. Furthermore, since they always want to show off that they are courageous, they will never leap to rocks downriver. Finally, since they never want to admit they have been defeated, they never land on a rock if the rock is already visited by other rabbits.
In this situation, is it possible for them to move to their destination rocks? If possible, please minimize the sum of their moving distance.
Input
The first line contains two integers $N$ ($1 \leq N \leq 100$), $K$ ($1 \leq K \leq 3$) and a real number $R$ ($0 \leq R \leq 10^4$), which denote the number of rocks, the number of rabbits, and the maximum distance a rabbit can leap, respectively. The second line contains $K$ numbers $s_1, ...,  s_K$ where $s_i$ denote the rock where the $i$-th rabbit is standing. Similarly, the third line contains $K$ numbers $t_1, ..., t_K$ where $t_i$ denote the destination rock for the $i$-th rabbit. $s_1, ..., s_K$ are distinct, and $t_1, ..., t_K$ are distinct. A destination rock of a rabbit is always different from the rock he/she is standing currently.
Then the following $N$ lines describe the positions of the rocks. The $i$-th line in this block contains two integers $x_i$ and $y_i$ ($0 \leq x_i, y_i \leq 10,000$), which indicate the coordinates of the $i$-th rock. The river flows along Y-axis, toward the direction where Y-coordinate decreases. No pair of rocks has identical coordinates.
You may assume that the answer do not change even if you increase $R$ by up to $10^{-5}$.
Output
If all the rabbits can move to their destination rocks, print the minimum total distance they need to leap. If not, print "-1" (without quotes). Your answer may contain at most $10^{-6}$ of absolute error.
Sample Input
6 3 1.0
1 2 3
4 5 6
0 0
1 0
2 0
0 1
1 1
2 1
Output for the Sample Input
3

Submitted solutions:

code_snippet: #include <iostream>
#include <algorithm>
#include <unordered_set>
#include <iomanip>
#include <vector>
#include <bitset>
#include <queue>
#include <cmath>
#include <unordered_map>

using namespace std;

const double INF = 1e100;
int N, K;
double R;

struct Point {
    int x, y;
};

long long keyEdge(int u, int v) { return 1LL * u * 1000000LL + v; } // unique if N<=1e6

int Gcd(int a, int b) {
  if (b == 0) {
    return a;
  }
  return Gcd(b, a % b);
}

pair<int,int> normDir(int dx, int dy) {
  if (dx == 0 && dy == 0) return {0,0};
  int g = Gcd(abs(dx), abs(dy));
  dx /= g; dy /= g;
  return {dx, dy};
}

struct Edge {
    int to;
    double w;
};

struct Path {
    vector<int> nodes;
    double cost;
    bitset<128> used; // N <= 100
    string sig;
};

string pathSig(const vector<int>& p) {
  string s;
  for (int i = 0; i < (int)p.size(); ++i) {
    if (i) s.push_back(',');
    s += to_string(p[i]);
  }
  return s;
}

// Dijkstra with forbidden vertices and forbidden edges; returns pair(cost,path) or empty if no path
pair<double, vector<int>> dijkstra_with_forbid(int s, int t,
                                               const vector<vector<Edge>>& adj,
                                               const vector<char>& forbidV,
                                               const unordered_set<long long>& forbidE) {
  int n = adj.size();
  vector<double> dist(n, INF);
  vector<int> parent(n, -1);
  using PDI = pair<double,int>;
  priority_queue<PDI, vector<PDI>, greater<PDI>> pq;
  if (forbidV[s]) return {INF, {}};
  dist[s] = 0.0;
  pq.push({0.0, s});
  while (!pq.empty()) {
    auto [d,u] = pq.top(); pq.pop();
    if (d > dist[u]) continue;
    if (u == t) break;
    for (auto &e : adj[u]) {
      int v = e.to;
      if (forbidV[v]) continue;
      if (forbidE.find(keyEdge(u,v)) != forbidE.end()) continue;
      double nd = d + e.w;
      if (nd + 1e-12 < dist[v]) {
        dist[v] = nd;
        parent[v] = u;
        pq.push({nd, v});
      }
    }
  }
  if (dist[t] >= INF/2) return {INF, {}};
  vector<int> path;
  int cur = t;
  while (cur != -1) { path.push_back(cur); cur = parent[cur]; }
  reverse(path.begin(), path.end());
  return {dist[t], path};
}

// Yen's algorithm to produce up to Kshort simple shortest paths between s and t
vector<Path> yenKshortest(int s, int t, const vector<vector<Edge>>& adj, int Kshort) {
  vector<Path> A;
  vector<char> noForbid(adj.size(), 0);
  unordered_set<long long> noForbidE;
  auto sp0 = dijkstra_with_forbid(s, t, adj, noForbid, noForbidE);
  if (!isfinite(sp0.first) || sp0.second.empty()) return A;
  Path p0;
  p0.nodes = sp0.second; p0.cost = sp0.first;
  p0.used.reset();
  for (int v: p0.nodes) p0.used.set(v);
  p0.sig = pathSig(p0.nodes);
  A.push_back(p0);

  // candidate container B (cost, path)
  using CP = pair<double, Path>;
  auto cmp = [](const CP &a, const CP &b){ return a.first > b.first; };
  priority_queue<CP, vector<CP>, decltype(cmp)> B(cmp);
  unordered_set<string> Bset; // signatures in B to avoid duplicates

  unordered_set<string> Aset;
  Aset.insert(p0.sig);

  int countK = 1;
  while (countK < Kshort) {
    const Path &prevPath = A[countK-1];
    int plen = (int)prevPath.nodes.size();
    for (int i = 0; i < plen - 1; ++i) {
      int spurNode = prevPath.nodes[i];
      // root path = nodes[0..i]
      vector<int> root(prevPath.nodes.begin(), prevPath.nodes.begin() + i + 1);
      double rootCost = 0.0;
      // compute rootCost by summing edge weights between root nodes
      for (int r = 0; r + 1 < (int)root.size(); ++r) {
        int uu = root[r], vv = root[r+1];
        // find weight
        double w = -1;
        for (auto &e : adj[uu]) if (e.to == vv) { w = e.w; break; }
        if (w < 0) { rootCost = INF; break; }
        rootCost += w;
      }
      if (rootCost >= INF/2) continue;

      // forbid edges for previous paths that share same root
      unordered_set<long long> forbidE;
      vector<char> forbidV(adj.size(), 0);
      for (auto &p : A) {
        // if p has same root
        if ((int)p.nodes.size() > i) {
          bool sameRoot = true;
          for (int r = 0; r <= i; ++r) {
            if (p.nodes[r] != root[r]) { sameRoot = false; break; }
          }
          if (sameRoot) {
            // forbid edge (p.nodes[i], p.nodes[i+1])
            forbidE.insert(keyEdge(p.nodes[i], p.nodes[i+1]));
          }
        }
      }
      // forbid nodes in root except spurNode
      for (int r = 0; r < (int)root.size()-1; ++r) forbidV[root[r]] = 1; // last of root is spurNode, keep it allowed
      auto spur = dijkstra_with_forbid(spurNode, t, adj, forbidV, forbidE);
      if (!isfinite(spur.first) || spur.second.empty()) continue;
      // total path = root(0..i-1) + spur path
      vector<int> total;
      for (int x: root) total.push_back(x);
      // spur.second begins with spurNode, so append from index 1
      for (int idx = 1; idx < (int)spur.second.size(); ++idx) total.push_back(spur.second[idx]);
      // build total cost
      double totalCost = rootCost + spur.first;
      // build signature
      string sig = pathSig(total);
      if (Aset.count(sig)) continue;
      if (Bset.count(sig)) continue;
      Path newp;
      newp.nodes = total;
      newp.cost = totalCost;
      newp.used.reset();
      for (int v: total) newp.used.set(v);
      newp.sig = sig;
      B.push({newp.cost, newp});
      Bset.insert(sig);
    }

    if (B.empty()) break;
    auto best = B.top(); B.pop();
    Path chosen = best.second;
    A.push_back(chosen);
    Aset.insert(chosen.sig);
    ++countK;
  }
  return A;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cin >> N >> K >> R;
  vector<int> s(K), t(K);
  for (int i = 0; i < K; ++i) { cin >> s[i]; --s[i]; }
  for (int i = 0; i < K; ++i) { cin >> t[i]; --t[i]; }
  vector<Point> pts(N);
  for (int i = 0; i < N; ++i) cin >> pts[i].x >> pts[i].y;

  // Build adjacency: for each u, for each direction keep nearest v (collinear check via normalized direction)
  vector<vector<Edge>> adj(N);
  double R2 = R * R;
  for (int u = 0; u < N; ++u) {
    // map normalized direction -> pair(dist2, v)
    unordered_map<long long, pair<long long,int>> best; // key from dx,dy to (dist2, v)
    best.reserve(N*2);
    for (int v = 0; v < N; ++v) if (v != u) {
        int dx = pts[v].x - pts[u].x;
        int dy = pts[v].y - pts[u].y;
        // cannot jump downriver: y_v >= y_u
        if (pts[v].y < pts[u].y) continue;
        auto nd = normDir(dx, dy);
        long long k = ( (long long)nd.first << 32 ) ^ (unsigned long long)(nd.second & 0xffffffff);
        long long dist2 = 1LL * dx * dx + 1LL * dy * dy;
        auto it = best.find(k);
        if (it == best.end() || dist2 < it->second.first) {
          best[k] = {dist2, v};
        }
      }
    for (auto &pr : best) {
      long long dist2 = pr.second.first;
      int v = pr.second.second;
      if ((double)dist2 <= R2 + 1e-9) {
        double w = sqrt((double)dist2);
        adj[u].push_back({v, w});
      }
    }
  }

  // Set how many candidate paths per pair to generate
  const int MAX_PATHS_PER_PAIR = 250;

  // For each pair generate K-shortest simple paths
  vector<vector<Path>> allPaths(K);
  for (int i = 0; i < K; ++i) {
    auto ps = yenKshortest(s[i], t[i], adj, MAX_PATHS_PER_PAIR);
    // sort by cost (yen already gives ascending but be safe)
    sort(ps.begin(), ps.end(), [](const Path& a, const Path& b){ return a.cost < b.cost; });
    allPaths[i] = move(ps);
    if (allPaths[i].empty()) {
      cout.setf(std::ios::fixed);
      cout<<setprecision(10)<<-1<<"\n";
      return 0;
    }
  }

  // Now pick disjoint combination with minimal total cost
  double best = INF;

  if (K == 1) {
    // minimal cost among paths for pair 0 (they are sorted)
    best = allPaths[0][0].cost;
  } else if (K == 2) {
    auto &A = allPaths[0];
    auto &Bv = allPaths[1];
    for (size_t i = 0; i < A.size(); ++i) {
      if (A[i].cost >= best) break;
      for (size_t j = 0; j < Bv.size(); ++j) {
        double sum = A[i].cost + Bv[j].cost;
        if (sum >= best) break;
        // check disjoint
        bitset<128> inter = A[i].used & Bv[j].used;
        if (inter.any()) continue;
        best = sum;
      }
    }
  } else if (K == 3) {
    auto &P0 = allPaths[0];
    auto &P1 = allPaths[1];
    auto &P2 = allPaths[2];
    for (size_t i = 0; i < P0.size(); ++i) {
      if (P0[i].cost >= best) break;
      for (size_t j = 0; j < P1.size(); ++j) {
        double sum2 = P0[i].cost + P1[j].cost;
        if (sum2 >= best) break;
        if ((P0[i].used & P1[j].used).any()) continue;
        for (size_t k = 0; k < P2.size(); ++k) {
          double sum3 = sum2 + P2[k].cost;
          if (sum3 >= best) break;
          if ((P0[i].used & P2[k].used).any()) continue;
          if ((P1[j].used & P2[k].used).any()) continue;
          best = sum3;
        }
      }
    }
  }

  if (best >= INF/2) {
    cout.setf(std::ios::fixed); cout<<setprecision(10)<<-1<<"\n";
  } else {
    cout.setf(std::ios::fixed); cout<<setprecision(10)<<best<<"\n";
  }

  return 0;
}
accuracy: 1
time_ms: 120
memory_kb: 9528
final_rank: 1

code_snippet: //#include <iostream>
//#include <algorithm>
//#include <unordered_set>
//#include <numeric>
//#include <iomanip>
#include <bits/stdc++.h>

using namespace std;

const double INF = 1e100;
int N, K;
double R;

struct Point {
    int x, y;
};

long long keyEdge(int u, int v) { return 1LL * u * 1000000LL + v; } // unique if N<=1e6

int Gcd(int a, int b) {
  if (b == 0) {
    return a;
  }
  return Gcd(b, a % b);
}

pair<int,int> normDir(int dx, int dy) {
  if (dx == 0 && dy == 0) return {0,0};
  int g = Gcd(abs(dx), abs(dy));
  dx /= g; dy /= g;
  return {dx, dy};
}

struct Edge {
    int to;
    double w;
};

struct Path {
    vector<int> nodes;
    double cost;
    bitset<128> used; // N <= 100
    string sig;
};

string pathSig(const vector<int>& p) {
  string s;
  for (int i = 0; i < (int)p.size(); ++i) {
    if (i) s.push_back(',');
    s += to_string(p[i]);
  }
  return s;
}

// Dijkstra with forbidden vertices and forbidden edges; returns pair(cost,path) or empty if no path
pair<double, vector<int>> dijkstra_with_forbid(int s, int t,
                                               const vector<vector<Edge>>& adj,
                                               const vector<char>& forbidV,
                                               const unordered_set<long long>& forbidE) {
  int n = adj.size();
  vector<double> dist(n, INF);
  vector<int> parent(n, -1);
  using PDI = pair<double,int>;
  priority_queue<PDI, vector<PDI>, greater<PDI>> pq;
  if (forbidV[s]) return {INF, {}};
  dist[s] = 0.0;
  pq.push({0.0, s});
  while (!pq.empty()) {
    auto [d,u] = pq.top(); pq.pop();
    if (d > dist[u]) continue;
    if (u == t) break;
    for (auto &e : adj[u]) {
      int v = e.to;
      if (forbidV[v]) continue;
      if (forbidE.find(keyEdge(u,v)) != forbidE.end()) continue;
      double nd = d + e.w;
      if (nd + 1e-12 < dist[v]) {
        dist[v] = nd;
        parent[v] = u;
        pq.push({nd, v});
      }
    }
  }
  if (dist[t] >= INF/2) return {INF, {}};
  vector<int> path;
  int cur = t;
  while (cur != -1) { path.push_back(cur); cur = parent[cur]; }
  reverse(path.begin(), path.end());
  return {dist[t], path};
}

// Yen's algorithm to produce up to Kshort simple shortest paths between s and t
vector<Path> yenKshortest(int s, int t, const vector<vector<Edge>>& adj, int Kshort) {
  vector<Path> A;
  vector<char> noForbid(adj.size(), 0);
  unordered_set<long long> noForbidE;
  auto sp0 = dijkstra_with_forbid(s, t, adj, noForbid, noForbidE);
  if (!isfinite(sp0.first) || sp0.second.empty()) return A;
  Path p0;
  p0.nodes = sp0.second; p0.cost = sp0.first;
  p0.used.reset();
  for (int v: p0.nodes) p0.used.set(v);
  p0.sig = pathSig(p0.nodes);
  A.push_back(p0);

  // candidate container B (cost, path)
  using CP = pair<double, Path>;
  auto cmp = [](const CP &a, const CP &b){ return a.first > b.first; };
  priority_queue<CP, vector<CP>, decltype(cmp)> B(cmp);
  unordered_set<string> Bset; // signatures in B to avoid duplicates

  unordered_set<string> Aset;
  Aset.insert(p0.sig);

  int countK = 1;
  while (countK < Kshort) {
    const Path &prevPath = A[countK-1];
    int plen = (int)prevPath.nodes.size();
    for (int i = 0; i < plen - 1; ++i) {
      int spurNode = prevPath.nodes[i];
      // root path = nodes[0..i]
      vector<int> root(prevPath.nodes.begin(), prevPath.nodes.begin() + i + 1);
      double rootCost = 0.0;
      // compute rootCost by summing edge weights between root nodes
      for (int r = 0; r + 1 < (int)root.size(); ++r) {
        int uu = root[r], vv = root[r+1];
        // find weight
        double w = -1;
        for (auto &e : adj[uu]) if (e.to == vv) { w = e.w; break; }
        if (w < 0) { rootCost = INF; break; }
        rootCost += w;
      }
      if (rootCost >= INF/2) continue;

      // forbid edges for previous paths that share same root
      unordered_set<long long> forbidE;
      vector<char> forbidV(adj.size(), 0);
      for (auto &p : A) {
        // if p has same root
        if ((int)p.nodes.size() > i) {
          bool sameRoot = true;
          for (int r = 0; r <= i; ++r) {
            if (p.nodes[r] != root[r]) { sameRoot = false; break; }
          }
          if (sameRoot) {
            // forbid edge (p.nodes[i], p.nodes[i+1])
            forbidE.insert(keyEdge(p.nodes[i], p.nodes[i+1]));
          }
        }
      }
      // forbid nodes in root except spurNode
      for (int r = 0; r < (int)root.size()-1; ++r) forbidV[root[r]] = 1; // last of root is spurNode, keep it allowed
      auto spur = dijkstra_with_forbid(spurNode, t, adj, forbidV, forbidE);
      if (!isfinite(spur.first) || spur.second.empty()) continue;
      // total path = root(0..i-1) + spur path
      vector<int> total;
      for (int x: root) total.push_back(x);
      // spur.second begins with spurNode, so append from index 1
      for (int idx = 1; idx < (int)spur.second.size(); ++idx) total.push_back(spur.second[idx]);
      // build total cost
      double totalCost = rootCost + spur.first;
      // build signature
      string sig = pathSig(total);
      if (Aset.count(sig)) continue;
      if (Bset.count(sig)) continue;
      Path newp;
      newp.nodes = total;
      newp.cost = totalCost;
      newp.used.reset();
      for (int v: total) newp.used.set(v);
      newp.sig = sig;
      B.push({newp.cost, newp});
      Bset.insert(sig);
    }

    if (B.empty()) break;
    auto best = B.top(); B.pop();
    Path chosen = best.second;
    A.push_back(chosen);
    Aset.insert(chosen.sig);
    ++countK;
  }
  return A;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cin >> N >> K >> R;
  vector<int> s(K), t(K);
  for (int i = 0; i < K; ++i) { cin >> s[i]; --s[i]; }
  for (int i = 0; i < K; ++i) { cin >> t[i]; --t[i]; }
  vector<Point> pts(N);
  for (int i = 0; i < N; ++i) cin >> pts[i].x >> pts[i].y;

  // Build adjacency: for each u, for each direction keep nearest v (collinear check via normalized direction)
  vector<vector<Edge>> adj(N);
  double R2 = R * R;
  for (int u = 0; u < N; ++u) {
    // map normalized direction -> pair(dist2, v)
    unordered_map<long long, pair<long long,int>> best; // key from dx,dy to (dist2, v)
    best.reserve(N*2);
    for (int v = 0; v < N; ++v) if (v != u) {
        int dx = pts[v].x - pts[u].x;
        int dy = pts[v].y - pts[u].y;
        // cannot jump downriver: y_v >= y_u
        if (pts[v].y < pts[u].y) continue;
        auto nd = normDir(dx, dy);
        long long k = ( (long long)nd.first << 32 ) ^ (unsigned long long)(nd.second & 0xffffffff);
        long long dist2 = 1LL * dx * dx + 1LL * dy * dy;
        auto it = best.find(k);
        if (it == best.end() || dist2 < it->second.first) {
          best[k] = {dist2, v};
        }
      }
    for (auto &pr : best) {
      long long dist2 = pr.second.first;
      int v = pr.second.second;
      if ((double)dist2 <= R2 + 1e-9) {
        double w = sqrt((double)dist2);
        adj[u].push_back({v, w});
      }
    }
  }

  // Set how many candidate paths per pair to generate
  const int MAX_PATHS_PER_PAIR = 250;

  // For each pair generate K-shortest simple paths
  vector<vector<Path>> allPaths(K);
  for (int i = 0; i < K; ++i) {
    auto ps = yenKshortest(s[i], t[i], adj, MAX_PATHS_PER_PAIR);
    // sort by cost (yen already gives ascending but be safe)
    sort(ps.begin(), ps.end(), [](const Path& a, const Path& b){ return a.cost < b.cost; });
    allPaths[i] = move(ps);
    if (allPaths[i].empty()) {
      cout.setf(std::ios::fixed);
      cout<<setprecision(10)<<-1<<"\n";
      return 0;
    }
  }

  // Now pick disjoint combination with minimal total cost
  double best = INF;

  if (K == 1) {
    // minimal cost among paths for pair 0 (they are sorted)
    best = allPaths[0][0].cost;
  } else if (K == 2) {
    auto &A = allPaths[0];
    auto &Bv = allPaths[1];
    for (size_t i = 0; i < A.size(); ++i) {
      if (A[i].cost >= best) break;
      for (size_t j = 0; j < Bv.size(); ++j) {
        double sum = A[i].cost + Bv[j].cost;
        if (sum >= best) break;
        // check disjoint
        bitset<128> inter = A[i].used & Bv[j].used;
        if (inter.any()) continue;
        best = sum;
      }
    }
  } else if (K == 3) {
    auto &P0 = allPaths[0];
    auto &P1 = allPaths[1];
    auto &P2 = allPaths[2];
    for (size_t i = 0; i < P0.size(); ++i) {
      if (P0[i].cost >= best) break;
      for (size_t j = 0; j < P1.size(); ++j) {
        double sum2 = P0[i].cost + P1[j].cost;
        if (sum2 >= best) break;
        if ((P0[i].used & P1[j].used).any()) continue;
        for (size_t k = 0; k < P2.size(); ++k) {
          double sum3 = sum2 + P2[k].cost;
          if (sum3 >= best) break;
          if ((P0[i].used & P2[k].used).any()) continue;
          if ((P1[j].used & P2[k].used).any()) continue;
          best = sum3;
        }
      }
    }
  }

  if (best >= INF/2) {
    cout.setf(std::ios::fixed); cout<<setprecision(10)<<-1<<"\n";
  } else {
    cout.setf(std::ios::fixed); cout<<setprecision(10)<<best<<"\n";
  }

  return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 9528
final_rank: 2

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 105
#define SIZE2 10005

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
		X = 0;
		Y = 0;
	}

	Point(){
		x = y = 0.0;
		X = Y = 0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{
		return x != p.x? x < p.x: y < p.y;
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}

   	/*
	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/

	double x,y;
	int X,Y;
};

typedef Point Vector;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};



struct Edge{
	Edge(int arg_to,double arg_dist){
		to = arg_to;
		dist = arg_dist;
	}
	int to;
	double dist;
};

struct State{
	State(int arg_node_id,double arg_sum_dist){
		node_id = arg_node_id;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct State &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int node_id;
	double sum_dist;
};

struct Info2{
	Info2(){

		loc[0] = loc[1] = 0;
		sum_dist = 0;
	}
	Info2(int arg_loc0,int arg_loc1,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info2 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}

	int loc[2];
	double sum_dist;
};

struct Info3{
	Info3(){

		loc[0] = loc[1] = loc[2] = 0;
		sum_dist = 0;
	}
	Info3(int arg_loc0,int arg_loc1,int arg_loc2,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		loc[2] = arg_loc2;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info3 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int loc[3];
	double sum_dist;
};

struct TWO{
	TWO(int arg_left,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_right;
	}
	int pos[2];
};

struct THREE{
	THREE(int arg_left,int arg_mid,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_mid;
		pos[2] = arg_right;
	}
	int pos[3];
};

struct Data{
	Data(int arg_p_id,int arg_loc_id){
		p_id = arg_p_id;
		loc_id = arg_loc_id;
	}
	bool operator<(const struct Data &arg) const{

		return p_id < arg.p_id;
	}

	int p_id,loc_id;
};


int N,num_dog;
int first_S[3],first_T[3];
int S[3],T[3];
int boss[SIZE],height[SIZE];
int L[SIZE],R[SIZE];
int work_L[3],work_R[3];
int num_point;
int min_Y,max_Y;
int ans_Y[3];
double D;
double dp[SIZE],dp2[SIZE][SIZE],dp3[SIZE][SIZE][SIZE];
double min_dist[SIZE][SIZE];
Point input[SIZE],point[SIZE];
vector<Point> P[SIZE2];
vector<Edge> G[SIZE];



int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		L[boss_y] = min(L[boss_y],L[boss_x]);
		R[boss_y] = max(R[boss_y],R[boss_x]);
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);

		boss[boss_y] = boss_x;
		height[x]++;
	}
}


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

void func1(){

	for(int i = 0; i < num_point; i++){

		dp[i] = BIG_NUM;
	}

	dp[S[0]] = 0;
	priority_queue<State> Q;

	Q.push(State(S[0],0));

	int next_node;
	double next_dist;

	while(!Q.empty()){

		if(Q.top().sum_dist > dp[Q.top().node_id]+EPS){

			Q.pop();
		}else if(Q.top().node_id == T[0]){

			printf("%.10lf\n",Q.top().sum_dist);
			return;

		}else{

			for(int i = 0; i < G[Q.top().node_id].size(); i++){

				next_node = G[Q.top().node_id][i].to;
				next_dist = Q.top().sum_dist+G[Q.top().node_id][i].dist;

				if(dp[next_node] > next_dist+EPS){
					dp[next_node] = next_dist;
					Q.push(State(next_node,next_dist));
				}
			}
			Q.pop();
		}
	}

	printf("-1\n");
}

vector<TWO> calc_pos2(int first_left,int first_right){

	vector<TWO> ret;
	int group_id = get_boss(first_left);

	for(int l = L[group_id]; l < first_right; l++){
		for(int r = max(l,first_left)+1; r <= R[group_id]; r++){

			ret.push_back(TWO(l,r));
		}
	}

	return ret;
}

vector<THREE> calc_pos3(int first_left,int first_mid,int first_right){

	vector<THREE> ret;
	int group_id = get_boss(first_left);

	for(int l = max(L[group_id],work_L[0]); l <= min(work_R[0],first_mid-1); l++){
		for(int m = max(max(l,first_left)+1,work_L[1]); m <= min(work_R[1],first_right-1); m++){
			for(int r = max(max(m,first_mid)+1,work_L[2]); r <= min(work_R[2],R[group_id]); r++){

				ret.push_back(THREE(l,m,r));
			}
		}
	}

	return ret;
}

void func2(){

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){
			dp2[i][k] = BIG_NUM;
		}
	}

	dp2[S[0]][S[1]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info2> Q[2];
	Q[CURRENT].push(Info2(S[0],S[1],0));

	bool STOP[2] = {false,false};
	bool used[2];

	int num_stop = 0;

	while(true){

		used[0] = false;
		used[1] = false;

		while(!Q[CURRENT].empty()){

			Info2 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			if(info.sum_dist > dp2[info.loc[0]][info.loc[1]]+EPS){

				continue;

			}else{

				if(num_stop == 1 || (num_stop == 0 &&get_boss(info.loc[0]) != get_boss(info.loc[1]))){

					if((STOP[1]) || (!STOP[0] && point[info.loc[0]].Y <= point[info.loc[1]].Y)){

						used[0] = true;

						for(int i = 0; i < G[info.loc[0]].size(); i++){

							int next_node = G[info.loc[0]][i].to;
							if(point[next_node].Y > ans_Y[0] || next_node == info.loc[1])continue;
							double next_dist = info.sum_dist+G[info.loc[0]][i].dist;

							if(dp2[next_node][info.loc[1]] > next_dist+EPS){
								dp2[next_node][info.loc[1]] = next_dist;
								Q[NEXT].push(Info2(next_node,info.loc[1],next_dist));
							}
						}

					}else{

						used[1] = true;

						for(int i = 0; i < G[info.loc[1]].size(); i++){

							int next_node = G[info.loc[1]][i].to;
							if(point[next_node].Y > ans_Y[1] || next_node == info.loc[0])continue;
							double next_dist = info.sum_dist+G[info.loc[1]][i].dist;

							if(dp2[info.loc[0]][next_node] > next_dist+EPS){
								dp2[info.loc[0]][next_node] = next_dist;
								Q[NEXT].push(Info2(info.loc[0],next_node,next_dist));
							}
						}
					}

				}else{ //同グループ

					used[0] = true;
					used[1] = true;

					vector<TWO> vec = calc_pos2(min(info.loc[0],info.loc[1]),max(info.loc[0],info.loc[1]));

					int next0,next1,dist0,dist1;

					for(int i = 0; i < vec.size(); i++){

						if(info.loc[0] < info.loc[1]){ //index順とXの大小は一致している

							next0 = vec[i].pos[0];
							next1 = vec[i].pos[1];

						}else{

							next0 = vec[i].pos[1];
							next1 = vec[i].pos[0];
						}

						dist0 = min_dist[info.loc[0]][next0];
						dist1 = min_dist[info.loc[1]][next1];

						double next_dist = info.sum_dist+dist0+dist1;


						if(dp2[next0][next1] > next_dist+EPS){
							dp2[next0][next1] = next_dist;
							//★★PQには突っ込まない★★
						}else if(fabs(dp2[next0][next1]-next_dist) < EPS){

							//★初期位置から動かず★

						}else{

							continue; //★★注意★★
						}

						int to_0,to_1;

						for(int a = 0; a < G[next0].size(); a++){

							to_0 = G[next0][a].to;
							if(point[info.loc[0]].Y == point[to_0].Y)continue;
							if(point[to_0].Y > ans_Y[0])continue;
							for(int b = 0; b < G[next1].size(); b++){
								to_1 = G[next1][b].to;
								if(point[info.loc[1]].Y == point[to_1].Y)continue;
								if(to_1 == to_0)continue;
								if(point[to_1].Y > ans_Y[1])continue;

								double tmp_dist = next_dist+G[next0][a].dist+G[next1][b].dist;
								if(dp2[to_0][to_1] > tmp_dist+EPS){
									dp2[to_0][to_1] = tmp_dist;
									Q[NEXT].push(Info2(to_0,to_1,tmp_dist));
								}
							}
						}
					}
				}
			}
		}

		if(Q[NEXT].size() == 0){
			if(!STOP[0] && used[0]){
				STOP[0] = true;
				num_stop++;
			}
			if(!STOP[1] && used[1]){
				STOP[1] = true;
				num_stop++;
			}

			if(num_stop == 2){

				break;
			}else{

				if(STOP[0]){

					for(int i = 0; i < num_point; i++){

						if(fabs(dp2[T[0]][i]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info2(T[0],i,dp2[T[0]][i]));
					}

				}else{

					for(int i = 0; i < num_point; i++){

						if(fabs(dp2[i][T[1]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info2(i,T[1],dp2[i][T[1]]));
					}
				}

				if(Q[NEXT].size() == 0){

					break;
				}
			}
		}

		swap(CURRENT,NEXT);
	}

	if(fabs(dp2[T[0]][T[1]]-BIG_NUM) < EPS){

		printf("-1\n");

	}else{

		printf("%.10lf\n",dp2[T[0]][T[1]]);
	}
}

void func3(){

	for(int a = 0; a < num_point; a++){
		for(int b = 0; b < num_point; b++){
			for(int c = 0; c < num_point; c++){

				dp3[a][b][c] = BIG_NUM;
			}
		}
	}

	dp3[S[0]][S[1]][S[2]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info3> Q[2];
	Q[CURRENT].push(Info3(S[0],S[1],S[2],0));

	int num_stop = 0;
	bool STOP[3] = {false,false,false};
	bool used[3];

	while(true){

		for(int i = 0; i < 3; i++){

			used[i] = false;
		}

		while(!Q[CURRENT].empty()){

			Info3 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			int minimum = BIG_NUM;
			int num_minimum = 0;
			int max_index = -1;

			for(int i = 0; i < 3; i++){

				if(STOP[i])continue;

				if(minimum > point[info.loc[i]].Y){
					minimum = point[info.loc[i]].Y;
					num_minimum = 1;
				}else if(minimum == point[info.loc[i]].Y){

					num_minimum++;
				}else{

					max_index = i;
				}
			}

			bool sameFLG = false;
			if(num_stop == 1){

				if(STOP[0]){

					if(get_boss(info.loc[1]) == get_boss(info.loc[2])){

						sameFLG = true;
					}

				}else if(STOP[1]){

					if(get_boss(info.loc[0]) == get_boss(info.loc[2])){

						sameFLG = true;
					}

				}else{

					if(get_boss(info.loc[1]) == get_boss(info.loc[2])){

						sameFLG = true;
					}
				}
			}

			if((num_minimum == 1) || (num_stop == 1 && !sameFLG) || (num_stop == 0 && get_boss(info.loc[0]) != get_boss(info.loc[1]) &&
					get_boss(info.loc[0]) != get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) != get_boss(info.loc[2]))){ //Yの最小値が1つ、または全てのグループが異なる

				int min_index;

				for(int i = 0; i < 3; i++){
					if(STOP[i])continue;

					if(point[info.loc[i]].Y == minimum){
						min_index = i;
						break;
					}
				}

				//動くのは一匹だけ

				int next[3];
				for(int k = 0; k < 3; k++){

					next[k] = info.loc[k];
				}

				used[min_index] = true;

				for(int i = 0; i < G[info.loc[min_index]].size(); i++){

					int next_node = G[info.loc[min_index]][i].to;
					if(next_node == info.loc[0] || next_node == info.loc[1] || next_node == info.loc[2])continue;
					if(point[next_node].Y > ans_Y[min_index])continue;

					double next_dist = info.sum_dist+G[info.loc[min_index]][i].dist;

					next[min_index] = next_node;

					if(dp3[next[0]][next[1]][next[2]] > next_dist+EPS){

						dp3[next[0]][next[1]][next[2]] = next_dist;
						Q[NEXT].push(Info3(next[0],next[1],next[2],next_dist));
					}
				}

			}else if(num_stop == 0 && get_boss(info.loc[0]) == get_boss(info.loc[1]) && get_boss(info.loc[0]) == get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) == get_boss(info.loc[2])){ //全てのグループが同じ

				used[0] = true;
				used[1] = true;
				used[2] = true;

				vector<Data> data;
				for(int i = 0; i < 3; i++){

					data.push_back(Data(info.loc[i],i));
					work_L[i] = -1;
					work_R[i] = BIG_NUM;
				}

				sort(data.begin(),data.end());

				for(int i = 0; i < 3; i++){

					if(point[info.loc[data[i].loc_id]].Y == ans_Y[data[i].loc_id]){

						work_L[i] = T[data[i].loc_id];
						work_R[i] = T[data[i].loc_id];
					}
				}

				vector<THREE> vec = calc_pos3(data[0].p_id,data[1].p_id,data[2].p_id);

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < vec.size(); i++){

					for(int k = 0; k < 3; k++){

						TMP[data[k].loc_id] = vec[i].pos[k];
						tmp_d[data[k].loc_id] = min_dist[info.loc[data[k].loc_id]][TMP[data[k].loc_id]];
					}

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

					}else if(fabs(dp3[TMP[0]][TMP[1]][TMP[2]]-next_dist) < EPS){

						//★初期位置から動かず★
					}else{

						continue; //★★
					}

					int to_0,to_1,to_2;

					for(int a = 0; a < G[TMP[0]].size(); a++){
						to_0 = G[TMP[0]][a].to;
						if(point[to_0].Y == point[info.loc[0]].Y)continue;
						if(point[to_0].Y > ans_Y[0])continue;
						for(int b = 0; b < G[TMP[1]].size(); b++){
							to_1 = G[TMP[1]][b].to;
							if(point[to_1].Y == point[info.loc[1]].Y)continue;
							if(point[to_1].Y > ans_Y[1])continue;
							if(to_1 == to_0)continue;
							for(int c = 0; c < G[TMP[2]].size(); c++){
								to_2 = G[TMP[2]][c].to;
								if(point[to_2].Y == point[info.loc[2]].Y)continue;
								if(point[to_2].Y > ans_Y[2])continue;
								if(to_2 == to_0 || to_2 == to_1)continue;

								double tmp_dist = next_dist+G[TMP[0]][a].dist+G[TMP[1]][b].dist+G[TMP[2]][c].dist;

								if(dp3[to_0][to_1][to_2] > tmp_dist+EPS){
									dp3[to_0][to_1][to_2] = tmp_dist;
									Q[NEXT].push(Info3(to_0,to_1,to_2,tmp_dist));
								}
							}
						}
					}
				}

			}else{ //グループが1匹+2匹で、2匹が下方,または1匹がストップ

				vector<Data> tmp_v;
				for(int i = 0; i < 3; i++){
					if(STOP[i])continue;
					if(point[info.loc[i]].Y == minimum){

						tmp_v.push_back(Data(info.loc[i],i));
						used[i] = true;
					}
				}

				sort(tmp_v.begin(),tmp_v.end());

				vector<TWO> vec = calc_pos2(tmp_v[0].p_id,tmp_v[1].p_id);

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < 3; i++){
					TMP[i] = info.loc[i];
					tmp_d[i] = 0;
				}

				for(int i = 0; i < vec.size(); i++){

					for(int k = 0; k < 2; k++){

						TMP[tmp_v[k].loc_id] = vec[i].pos[k];
						tmp_d[tmp_v[k].loc_id] = min_dist[info.loc[tmp_v[k].loc_id]][TMP[tmp_v[k].loc_id]];
					}

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

					}else if(fabs(dp3[TMP[0]][TMP[1]][TMP[2]]-next_dist) < EPS){

						//★初期位置から動かず★

					}else{

						continue; //★★
					}

					int to[3];
					for(int a = 0; a < 3; a++){

						to[a] = TMP[a];
					}

					for(int a = 0; a < G[tmp_v[0].loc_id].size(); a++){
						to[tmp_v[0].loc_id] = G[tmp_v[0].loc_id][a].to;
						if(point[to[tmp_v[0].loc_id]].Y == minimum)continue;
						if(point[to[tmp_v[0].loc_id]].Y > ans_Y[tmp_v[0].loc_id])continue;
						if(to[tmp_v[0].loc_id] == max_index)continue;

						for(int b = 0; b < G[tmp_v[1].loc_id].size(); b++){
							to[tmp_v[1].loc_id] = G[tmp_v[1].loc_id][b].to;
							if(point[to[tmp_v[1].loc_id]].Y == minimum)continue;
							if(point[to[tmp_v[1].loc_id]].Y > ans_Y[tmp_v[1].loc_id])continue;
							if(to[tmp_v[1].loc_id] == max_index || to[tmp_v[1].loc_id] == to[tmp_v[0].loc_id])continue;

							double tmp_dist = next_dist+G[tmp_v[0].loc_id][a].dist+G[tmp_v[1].loc_id][b].dist;

							if(dp3[to[0]][to[1]][to[2]] > tmp_dist+EPS){

								dp3[to[0]][to[1]][to[2]] = tmp_dist;
								Q[NEXT].push(Info3(to[0],to[1],to[2],tmp_dist));
							}
						}
					}
				}
			}
		}

		if(Q[NEXT].size() == 0){
			if(!STOP[0] && used[0]){
				STOP[0] = true;
				num_stop++;
			}
			if(!STOP[1] && used[1]){
				STOP[1] = true;
				num_stop++;
			}
			if(!STOP[2] && used[2]){
				STOP[2] = true;
				num_stop++;
			}
			if(num_stop == 3){

				break;
			}

			if(num_stop == 1){

				for(int i = 0; i < num_point; i++){
					for(int k = 0; k < num_point; k++){

						if(STOP[0]){

							if(fabs(dp3[T[0]][i][k]-BIG_NUM) < EPS){

								continue;
							}
							Q[NEXT].push(Info3(T[0],i,k,dp3[T[0]][i][k]));

						}else if(STOP[1]){

							if(fabs(dp3[i][T[1]][k]-BIG_NUM) < EPS){

								continue;
							}
							Q[NEXT].push(Info3(i,T[1],k,dp3[i][T[1]][k]));


						}else{ //STOP[2]

							if(fabs(dp3[i][k][T[2]]-BIG_NUM) < EPS)continue;

							Q[NEXT].push(Info3(i,k,T[2],dp3[i][k][T[2]]));
						}
					}
				}

			}else{ //num_stop == 2

				for(int i = 0; i < num_point; i++){

					if(!STOP[0]){

						if(fabs(dp3[i][T[1]][T[2]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(i,T[1],T[2],dp3[i][T[1]][T[2]]));

					}else if(!STOP[1]){

						if(fabs(dp3[T[0]][i][T[2]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(T[0],i,T[2],dp3[T[0]][i][T[2]]));

					}else{ //!STOP[2]

						if(fabs(dp3[T[0]][T[1]][i]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(T[0],T[1],i,dp3[T[0]][T[1]][i]));
					}
				}
			}

			if(Q[NEXT].size() == 0){

				break;
			}
		}

		swap(CURRENT,NEXT);
	}

	if(fabs(dp3[T[0]][T[1]][T[2]]-BIG_NUM) < EPS){

		printf("-1\n");
	}else{

		printf("%.10lf\n",dp3[T[0]][T[1]][T[2]]);
	}
}

int main(){

	scanf("%d %d",&N,&num_dog);
	scanf("%lf",&D);

	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_S[i]);
		first_S[i]--;
	}
	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_T[i]);
		first_T[i]--;
	}

	min_Y = BIG_NUM,max_Y = -BIG_NUM;

	for(int i = 0; i < N; i++){

		scanf("%d %d",&input[i].X,&input[i].Y);
		input[i].x = input[i].X;
		input[i].y = input[i].Y;

		min_Y = min(min_Y,input[i].Y);
		max_Y = max(max_Y,input[i].Y);

		P[input[i].Y].push_back(input[i]);
	}

	num_point = 0;

	for(int i = min_Y; i <= max_Y; i++){
		if(P[i].size() == 0)continue;

		sort(P[i].begin(),P[i].end());

		point[num_point++] = P[i][0];

		for(int k = 1; k < P[i].size(); k++){

			point[num_point++] = P[i][k];
		}
	}

	for(int i = 0; i < num_dog; i++){
		for(int k = 0; k < num_point; k++){
			if(input[first_S[i]] == point[k]){

				S[i] = k;
			}
			if(input[first_T[i]] == point[k]){

				T[i] = k;
			}
		}
	}

	for(int i = 0; i < num_point; i++){

		boss[i] = i;
		height[i] = i;
		L[i] = i;
		R[i] = i;
	}

	for(int i = 0; i < num_dog; i++){

		ans_Y[i] = point[T[i]].Y;
	}

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){

			if(k == i){

				min_dist[i][k] = 0;
			}else{

				min_dist[i][k] = BIG_NUM;
			}
		}
	}

	//エッジ張り
	for(int i = 0; i < num_point-1; i++){
		for(int k = i+1; k < num_point; k++){
			if(calc_dist(point[i],point[k]) > D+EPS)continue;

			bool FLG = true;
			Line tmp_line = Line(point[i],point[k]);
			for(int a = 0; a < num_point; a++){
				if(a == i || a == k)continue;

				if(getDistanceSP(tmp_line,point[a]) < EPS){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			if(point[i].Y == point[k].Y){

				unite(i,k);
				double tmp_dist = calc_dist(point[i],point[k]);
				G[i].push_back(Edge(k,tmp_dist));
				G[k].push_back(Edge(i,tmp_dist));

				min_dist[i][k] = tmp_dist;
				min_dist[k][i] = tmp_dist;

			}else{

				int from = i;
				int to = k;
				if(point[i].Y > point[k].Y){

					swap(from,to);
				}
				G[from].push_back(Edge(to,calc_dist(point[i],point[k])));
			}
		}
	}

	for(int mid = 0; mid < num_point; mid++){
		for(int start = 0; start < num_point; start++){
			if(fabs(min_dist[start][mid]-BIG_NUM) < EPS)continue;
			for(int goal = 0; goal < num_point; goal++){
				if(fabs(min_dist[mid][goal]-BIG_NUM) < EPS)continue;

				min_dist[start][goal] = min(min_dist[start][goal],min_dist[start][mid]+min_dist[mid][goal]);
			}
		}
	}

	if(num_dog == 1){

		func1();

	}else if(num_dog == 2){

		func2();

	}else{

		func3();
	}

	return 0;
}
accuracy: 1
time_ms: 600
memory_kb: 36812
final_rank: 5

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 105
#define SIZE2 10005

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
		X = 0;
		Y = 0;
	}

	Point(){
		x = y = 0.0;
		X = Y = 0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{
		return x != p.x? x < p.x: y < p.y;
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}

   	/*
	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/

	double x,y;
	int X,Y;
};

typedef Point Vector;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};



struct Edge{
	Edge(int arg_to,double arg_dist){
		to = arg_to;
		dist = arg_dist;
	}
	int to;
	double dist;
};

struct State{
	State(int arg_node_id,double arg_sum_dist){
		node_id = arg_node_id;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct State &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int node_id;
	double sum_dist;
};

struct Info2{
	Info2(){

		loc[0] = loc[1] = 0;
		sum_dist = 0;
	}
	Info2(int arg_loc0,int arg_loc1,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info2 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}

	int loc[2];
	double sum_dist;
};

struct Info3{
	Info3(){

		loc[0] = loc[1] = loc[2] = 0;
		sum_dist = 0;
	}
	Info3(int arg_loc0,int arg_loc1,int arg_loc2,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		loc[2] = arg_loc2;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info3 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int loc[3];
	double sum_dist;
};

struct TWO{
	TWO(int arg_left,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_right;
	}
	int pos[2];
};

struct THREE{
	THREE(int arg_left,int arg_mid,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_mid;
		pos[2] = arg_right;
	}
	int pos[3];
};

struct Data{
	Data(int arg_p_id,int arg_loc_id){
		p_id = arg_p_id;
		loc_id = arg_loc_id;
	}
	bool operator<(const struct Data &arg) const{

		return p_id < arg.p_id;
	}

	int p_id,loc_id;
};


int N,num_dog;
int first_S[3],first_T[3];
int S[3],T[3];
int boss[SIZE],height[SIZE];
int L[SIZE],R[SIZE];
int work_L[3],work_R[3];
int num_point;
int min_Y,max_Y;
int ans_Y[3];
double D;
double dp[SIZE],dp2[SIZE][SIZE],dp3[SIZE][SIZE][SIZE];
double min_dist[SIZE][SIZE];
Point input[SIZE],point[SIZE];
vector<Point> P[SIZE2];
vector<Edge> G[SIZE];



int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		L[boss_y] = min(L[boss_y],L[boss_x]);
		R[boss_y] = max(R[boss_y],R[boss_x]);
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);

		boss[boss_y] = boss_x;
		height[x]++;
	}
}


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

void func1(){

	for(int i = 0; i < num_point; i++){

		dp[i] = BIG_NUM;
	}

	dp[S[0]] = 0;
	priority_queue<State> Q;

	Q.push(State(S[0],0));

	int next_node;
	double next_dist;

	while(!Q.empty()){

		if(Q.top().sum_dist > dp[Q.top().node_id]+EPS){

			Q.pop();
		}else if(Q.top().node_id == T[0]){

			printf("%.10lf\n",Q.top().sum_dist);
			return;

		}else{

			for(int i = 0; i < G[Q.top().node_id].size(); i++){

				next_node = G[Q.top().node_id][i].to;
				next_dist = Q.top().sum_dist+G[Q.top().node_id][i].dist;

				if(dp[next_node] > next_dist+EPS){
					dp[next_node] = next_dist;
					Q.push(State(next_node,next_dist));
				}
			}
			Q.pop();
		}
	}

	printf("-1\n");
}

vector<TWO> calc_pos2(int first_left,int first_right){

	vector<TWO> ret;
	int group_id = get_boss(first_left);

	for(int l = L[group_id]; l < first_right; l++){
		for(int r = max(l,first_left)+1; r <= R[group_id]; r++){

			ret.push_back(TWO(l,r));
		}
	}

	return ret;
}

vector<THREE> calc_pos3(int first_left,int first_mid,int first_right){

	vector<THREE> ret;
	int group_id = get_boss(first_left);

	for(int l = max(L[group_id],work_L[0]); l <= min(work_R[0],first_mid-1); l++){
		for(int m = max(max(l,first_left)+1,work_L[1]); m <= min(work_R[1],first_right-1); m++){
			for(int r = max(max(m,first_mid)+1,work_L[2]); r <= min(work_R[2],R[group_id]); r++){

				ret.push_back(THREE(l,m,r));
			}
		}
	}

	return ret;
}

void func2(){

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){
			dp2[i][k] = BIG_NUM;
		}
	}

	dp2[S[0]][S[1]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info2> Q[2];
	Q[CURRENT].push(Info2(S[0],S[1],0));

	bool STOP[2] = {false,false};
	bool used[2];

	int num_stop = 0;

	while(true){

		used[0] = false;
		used[1] = false;

		while(!Q[CURRENT].empty()){

			Info2 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			if(info.sum_dist > dp2[info.loc[0]][info.loc[1]]+EPS){

				continue;

			}else{

				if(num_stop == 1 || (num_stop == 0 &&get_boss(info.loc[0]) != get_boss(info.loc[1]))){

					if((STOP[1]) || (!STOP[0] && point[info.loc[0]].Y <= point[info.loc[1]].Y)){

						used[0] = true;

						for(int i = 0; i < G[info.loc[0]].size(); i++){

							int next_node = G[info.loc[0]][i].to;
							if(point[next_node].Y > ans_Y[0] || next_node == info.loc[1])continue;
							double next_dist = info.sum_dist+G[info.loc[0]][i].dist;

							if(dp2[next_node][info.loc[1]] > next_dist+EPS){
								dp2[next_node][info.loc[1]] = next_dist;
								Q[NEXT].push(Info2(next_node,info.loc[1],next_dist));
							}
						}

					}else{

						used[1] = true;

						for(int i = 0; i < G[info.loc[1]].size(); i++){

							int next_node = G[info.loc[1]][i].to;
							if(point[next_node].Y > ans_Y[1] || next_node == info.loc[0])continue;
							double next_dist = info.sum_dist+G[info.loc[1]][i].dist;

							if(dp2[info.loc[0]][next_node] > next_dist+EPS){
								dp2[info.loc[0]][next_node] = next_dist;
								Q[NEXT].push(Info2(info.loc[0],next_node,next_dist));
							}
						}
					}

				}else{ //同グループ

					used[0] = true;
					used[1] = true;

					vector<TWO> vec = calc_pos2(min(info.loc[0],info.loc[1]),max(info.loc[0],info.loc[1]));

					int next0,next1,dist0,dist1;

					for(int i = 0; i < vec.size(); i++){

						if(info.loc[0] < info.loc[1]){ //index順とXの大小は一致している

							next0 = vec[i].pos[0];
							next1 = vec[i].pos[1];

						}else{

							next0 = vec[i].pos[1];
							next1 = vec[i].pos[0];
						}

						dist0 = min_dist[info.loc[0]][next0];
						dist1 = min_dist[info.loc[1]][next1];

						double next_dist = info.sum_dist+dist0+dist1;


						if(dp2[next0][next1] > next_dist+EPS){
							dp2[next0][next1] = next_dist;
							//★★PQには突っ込まない★★
						}else if(fabs(dp2[next0][next1]-next_dist) < EPS){

							//★初期位置から動かず★

						}else{

							continue; //★★注意★★
						}

						int to_0,to_1;

						for(int a = 0; a < G[next0].size(); a++){

							to_0 = G[next0][a].to;
							if(point[info.loc[0]].Y == point[to_0].Y)continue;
							if(point[to_0].Y > ans_Y[0])continue;
							for(int b = 0; b < G[next1].size(); b++){
								to_1 = G[next1][b].to;
								if(point[info.loc[1]].Y == point[to_1].Y)continue;
								if(to_1 == to_0)continue;
								if(point[to_1].Y > ans_Y[1])continue;

								double tmp_dist = next_dist+G[next0][a].dist+G[next1][b].dist;
								if(dp2[to_0][to_1] > tmp_dist+EPS){
									dp2[to_0][to_1] = tmp_dist;
									Q[NEXT].push(Info2(to_0,to_1,tmp_dist));
								}
							}
						}
					}
				}
			}
		}

		if(Q[NEXT].size() == 0){
			if(!STOP[0] && used[0]){
				STOP[0] = true;
				num_stop++;
			}
			if(!STOP[1] && used[1]){
				STOP[1] = true;
				num_stop++;
			}

			if(num_stop == 2){

				break;
			}else{

				if(STOP[0]){

					for(int i = 0; i < num_point; i++){

						if(fabs(dp2[T[0]][i]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info2(T[0],i,dp2[T[0]][i]));
					}

				}else{

					for(int i = 0; i < num_point; i++){

						if(fabs(dp2[i][T[1]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info2(i,T[1],dp2[i][T[1]]));
					}
				}

				if(Q[NEXT].size() == 0){

					break;
				}
			}
		}

		swap(CURRENT,NEXT);
	}

	if(fabs(dp2[T[0]][T[1]]-BIG_NUM) < EPS){

		printf("-1\n");

	}else{

		printf("%.10lf\n",dp2[T[0]][T[1]]);
	}
}

void func3(){

	for(int a = 0; a < num_point; a++){
		for(int b = 0; b < num_point; b++){
			for(int c = 0; c < num_point; c++){

				dp3[a][b][c] = BIG_NUM;
			}
		}
	}

	dp3[S[0]][S[1]][S[2]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info3> Q[2];
	Q[CURRENT].push(Info3(S[0],S[1],S[2],0));

	int num_stop = 0;
	bool STOP[3] = {false,false,false};
	bool used[3];

	while(true){

		//printf("num_stop:%d\n",num_stop);

		for(int i = 0; i < 3; i++){

			used[i] = false;
		}

		while(!Q[CURRENT].empty()){

			Info3 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			int minimum = BIG_NUM;
			int num_minimum = 0;
			int max_index = -1;

			for(int i = 0; i < 3; i++){

				if(STOP[i])continue;

				if(minimum > point[info.loc[i]].Y){
					minimum = point[info.loc[i]].Y;
					num_minimum = 1;
				}else if(minimum == point[info.loc[i]].Y){

					num_minimum++;
				}else{

					max_index = i;
				}
			}

			bool sameFLG = false;
			if(num_stop == 1){

				if(STOP[0]){

					if(get_boss(info.loc[1]) == get_boss(info.loc[2])){

						sameFLG = true;
					}

				}else if(STOP[1]){

					if(get_boss(info.loc[0]) == get_boss(info.loc[2])){

						sameFLG = true;
					}

				}else{

					if(get_boss(info.loc[1]) == get_boss(info.loc[2])){

						sameFLG = true;
					}
				}
			}

			if((num_minimum == 1) || (num_stop == 1 && !sameFLG) || (num_stop == 0 && get_boss(info.loc[0]) != get_boss(info.loc[1]) &&
					get_boss(info.loc[0]) != get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) != get_boss(info.loc[2]))){ //Yの最小値が1つ、または全てのグループが異なる

				int min_index;

				for(int i = 0; i < 3; i++){
					if(STOP[i])continue;

					if(point[info.loc[i]].Y == minimum){
						min_index = i;
						break;
					}
				}

				//動くのは一匹だけ

				int next[3];
				for(int k = 0; k < 3; k++){

					next[k] = info.loc[k];
				}

				used[min_index] = true;

				for(int i = 0; i < G[info.loc[min_index]].size(); i++){

					int next_node = G[info.loc[min_index]][i].to;
					if(next_node == info.loc[0] || next_node == info.loc[1] || next_node == info.loc[2])continue;
					if(point[next_node].Y > ans_Y[min_index])continue;

					double next_dist = info.sum_dist+G[info.loc[min_index]][i].dist;

					next[min_index] = next_node;

					if(dp3[next[0]][next[1]][next[2]] > next_dist+EPS){

						dp3[next[0]][next[1]][next[2]] = next_dist;
						Q[NEXT].push(Info3(next[0],next[1],next[2],next_dist));
					}
				}

			}else if(num_stop == 0 && get_boss(info.loc[0]) == get_boss(info.loc[1]) && get_boss(info.loc[0]) == get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) == get_boss(info.loc[2])){ //全てのグループが同じ

				//printf("全てのグループが同じ\n");
				//printf("L:%d R:%d\n",L[get_boss(info.loc[0])],R[get_boss(info.loc[0])]);
				//return;

				used[0] = true;
				used[1] = true;
				used[2] = true;

				vector<Data> data;
				for(int i = 0; i < 3; i++){

					data.push_back(Data(info.loc[i],i));
					work_L[i] = -1;
					work_R[i] = BIG_NUM;
				}

				sort(data.begin(),data.end());

				for(int i = 0; i < 3; i++){

					if(point[info.loc[data[i].loc_id]].Y == ans_Y[data[i].loc_id]){

						work_L[i] = T[data[i].loc_id];
						work_R[i] = T[data[i].loc_id];
					}
				}

				/*for(int i = 0; i < 3; i++){

					printf("p_id[%d]:%d\n",i,data[i].p_id);
				}*/

				//printf("L:%d R:%d\n",L[get_boss(data[0].p_id)],R[get_boss(data[0].p_id)]);

				vector<THREE> vec = calc_pos3(data[0].p_id,data[1].p_id,data[2].p_id);

				//printf("vec.size():%lld\n",vec.size());

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < vec.size(); i++){

					//printf("\ni:%d\n",i);

					for(int k = 0; k < 3; k++){

						TMP[data[k].loc_id] = vec[i].pos[k];
						tmp_d[data[k].loc_id] = min_dist[info.loc[data[k].loc_id]][TMP[data[k].loc_id]];
					}

					/*for(int k = 0; k < 3; k++){

						printf("TMP[%d]:%d\n",k,TMP[k]);
						printf("dist:%.3lf\n",tmp_d[k]);
					}*/

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

						//printf("最小値更新\n");

					}else if(fabs(dp3[TMP[0]][TMP[1]][TMP[2]]-next_dist) < EPS){

						//★初期位置から動かず★
						//printf("動かず\n");

					}else{

						//printf("不適\n");
						continue; //★★
					}

					int to_0,to_1,to_2;

					ll debug = 0;

					for(int a = 0; a < G[TMP[0]].size(); a++){
						to_0 = G[TMP[0]][a].to;
						if(point[to_0].Y == point[info.loc[0]].Y)continue;
						if(point[to_0].Y > ans_Y[0])continue;
						for(int b = 0; b < G[TMP[1]].size(); b++){
							to_1 = G[TMP[1]][b].to;
							if(point[to_1].Y == point[info.loc[1]].Y)continue;
							if(point[to_1].Y > ans_Y[1])continue;
							if(to_1 == to_0)continue;
							for(int c = 0; c < G[TMP[2]].size(); c++){
								to_2 = G[TMP[2]][c].to;
								if(point[to_2].Y == point[info.loc[2]].Y)continue;
								if(point[to_2].Y > ans_Y[2])continue;
								if(to_2 == to_0 || to_2 == to_1)continue;

								double tmp_dist = next_dist+G[TMP[0]][a].dist+G[TMP[1]][b].dist+G[TMP[2]][c].dist;

								if(dp3[to_0][to_1][to_2] > tmp_dist+EPS){
									debug++;
									dp3[to_0][to_1][to_2] = tmp_dist;
									Q[NEXT].push(Info3(to_0,to_1,to_2,tmp_dist));
								}
							}
						}
					}
				}

				/*printf("Q[CURRENT].size():%lld Q[NEXT].size():%lld\n",Q[CURRENT].size(),Q[NEXT].size());
				return;*/

			}else{ //グループが1匹+2匹で、2匹が下方,または1匹がストップ

				vector<Data> tmp_v;
				for(int i = 0; i < 3; i++){
					if(STOP[i])continue;
					if(point[info.loc[i]].Y == minimum){

						tmp_v.push_back(Data(info.loc[i],i));
						used[i] = true;
					}
				}

				sort(tmp_v.begin(),tmp_v.end());

				vector<TWO> vec = calc_pos2(tmp_v[0].p_id,tmp_v[1].p_id);

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < 3; i++){
					TMP[i] = info.loc[i];
					tmp_d[i] = 0;
				}

				for(int i = 0; i < vec.size(); i++){

					for(int k = 0; k < 2; k++){

						TMP[tmp_v[k].loc_id] = vec[i].pos[k];
						tmp_d[tmp_v[k].loc_id] = min_dist[info.loc[tmp_v[k].loc_id]][TMP[tmp_v[k].loc_id]];
					}

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

					}else if(fabs(dp3[TMP[0]][TMP[1]][TMP[2]]-next_dist) < EPS){

						//★初期位置から動かず★

					}else{

						continue; //★★
					}

					int to[3];
					for(int a = 0; a < 3; a++){

						to[a] = TMP[a];
					}

					for(int a = 0; a < G[tmp_v[0].loc_id].size(); a++){
						to[tmp_v[0].loc_id] = G[tmp_v[0].loc_id][a].to;
						if(point[to[tmp_v[0].loc_id]].Y == minimum)continue;
						if(point[to[tmp_v[0].loc_id]].Y > ans_Y[tmp_v[0].loc_id])continue;
						if(to[tmp_v[0].loc_id] == max_index)continue;

						for(int b = 0; b < G[tmp_v[1].loc_id].size(); b++){
							to[tmp_v[1].loc_id] = G[tmp_v[1].loc_id][b].to;
							if(point[to[tmp_v[1].loc_id]].Y == minimum)continue;
							if(point[to[tmp_v[1].loc_id]].Y > ans_Y[tmp_v[1].loc_id])continue;
							if(to[tmp_v[1].loc_id] == max_index || to[tmp_v[1].loc_id] == to[tmp_v[0].loc_id])continue;

							double tmp_dist = next_dist+G[tmp_v[0].loc_id][a].dist+G[tmp_v[1].loc_id][b].dist;

							if(dp3[to[0]][to[1]][to[2]] > tmp_dist+EPS){

								dp3[to[0]][to[1]][to[2]] = tmp_dist;
								Q[NEXT].push(Info3(to[0],to[1],to[2],tmp_dist));
							}
						}
					}
				}
			}
		}

		/*printf("Q[NEXT].size():%lld num_stop:%d\n",Q[NEXT].size(),num_stop);
							break;*/

		if(Q[NEXT].size() == 0){
			if(!STOP[0] && used[0]){
				STOP[0] = true;
				num_stop++;
			}
			if(!STOP[1] && used[1]){
				STOP[1] = true;
				num_stop++;
			}
			if(!STOP[2] && used[2]){
				STOP[2] = true;
				num_stop++;
			}
			if(num_stop == 3){

				break;
			}

			if(num_stop == 1){

				for(int i = 0; i < num_point; i++){
					for(int k = 0; k < num_point; k++){

						if(STOP[0]){

							if(fabs(dp3[T[0]][i][k]-BIG_NUM) < EPS){

								continue;
							}
							Q[NEXT].push(Info3(T[0],i,k,dp3[T[0]][i][k]));

						}else if(STOP[1]){

							if(fabs(dp3[i][T[1]][k]-BIG_NUM) < EPS){

								continue;
							}
							Q[NEXT].push(Info3(i,T[1],k,dp3[i][T[1]][k]));


						}else{ //STOP[2]

							if(fabs(dp3[i][k][T[2]]-BIG_NUM) < EPS)continue;

							Q[NEXT].push(Info3(i,k,T[2],dp3[i][k][T[2]]));
						}
					}
				}

			}else{ //num_stop == 2

				for(int i = 0; i < num_point; i++){

					if(!STOP[0]){

						if(fabs(dp3[i][T[1]][T[2]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(i,T[1],T[2],dp3[i][T[1]][T[2]]));

					}else if(!STOP[1]){

						if(fabs(dp3[T[0]][i][T[2]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(T[0],i,T[2],dp3[T[0]][i][T[2]]));

					}else{ //!STOP[2]

						if(fabs(dp3[T[0]][T[1]][i]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(T[0],T[1],i,dp3[T[0]][T[1]][i]));
					}
				}
			}

			if(Q[NEXT].size() == 0){

				break;
			}
		}

		swap(CURRENT,NEXT);
	}

	if(fabs(dp3[T[0]][T[1]][T[2]]-BIG_NUM) < EPS){

		printf("-1\n");
	}else{

		printf("%.10lf\n",dp3[T[0]][T[1]][T[2]]);
	}
}

int main(){

	scanf("%d %d",&N,&num_dog);
	scanf("%lf",&D);

	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_S[i]);
		first_S[i]--;
	}
	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_T[i]);
		first_T[i]--;
	}

	min_Y = BIG_NUM,max_Y = -BIG_NUM;

	for(int i = 0; i < N; i++){

		scanf("%d %d",&input[i].X,&input[i].Y);
		input[i].x = input[i].X;
		input[i].y = input[i].Y;

		min_Y = min(min_Y,input[i].Y);
		max_Y = max(max_Y,input[i].Y);

		P[input[i].Y].push_back(input[i]);
	}

	num_point = 0;

	for(int i = min_Y; i <= max_Y; i++){
		if(P[i].size() == 0)continue;

		sort(P[i].begin(),P[i].end());

		point[num_point++] = P[i][0];

		for(int k = 1; k < P[i].size(); k++){

			point[num_point++] = P[i][k];
		}
	}

	for(int i = 0; i < num_dog; i++){
		for(int k = 0; k < num_point; k++){
			if(input[first_S[i]] == point[k]){

				S[i] = k;
			}
			if(input[first_T[i]] == point[k]){

				T[i] = k;
			}
		}
	}

	for(int i = 0; i < num_point; i++){

		boss[i] = i;
		height[i] = i;
		L[i] = i;
		R[i] = i;
	}

	for(int i = 0; i < num_dog; i++){

		ans_Y[i] = point[T[i]].Y;
	}

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){

			if(k == i){

				min_dist[i][k] = 0;
			}else{

				min_dist[i][k] = BIG_NUM;
			}
		}
	}

	//エッジ張り
	for(int i = 0; i < num_point-1; i++){
		for(int k = i+1; k < num_point; k++){
			if(calc_dist(point[i],point[k]) > D+EPS)continue;

			bool FLG = true;
			Line tmp_line = Line(point[i],point[k]);
			for(int a = 0; a < num_point; a++){
				if(a == i || a == k)continue;

				if(getDistanceSP(tmp_line,point[a]) < EPS){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			if(point[i].Y == point[k].Y){

				unite(i,k);
				double tmp_dist = calc_dist(point[i],point[k]);
				G[i].push_back(Edge(k,tmp_dist));
				G[k].push_back(Edge(i,tmp_dist));

				min_dist[i][k] = tmp_dist;
				min_dist[k][i] = tmp_dist;
				//printf("%d-%dにエッジを張った\n",i,k);

			}else{

				int from = i;
				int to = k;
				if(point[i].Y > point[k].Y){

					swap(from,to);
				}
				G[from].push_back(Edge(to,calc_dist(point[i],point[k])));
				//printf("%d-%dにエッジを張った\n",from,to);
			}
		}
	}

	for(int mid = 0; mid < num_point; mid++){
		for(int start = 0; start < num_point; start++){
			if(fabs(min_dist[start][mid]-BIG_NUM) < EPS)continue;
			for(int goal = 0; goal < num_point; goal++){
				if(fabs(min_dist[mid][goal]-BIG_NUM) < EPS)continue;

				min_dist[start][goal] = min(min_dist[start][goal],min_dist[start][mid]+min_dist[mid][goal]);
			}
		}
	}

	if(num_dog == 1){

		func1();

	}else if(num_dog == 2){

		func2();

	}else{

		func3();
	}

	return 0;
}
accuracy: 1
time_ms: 620
memory_kb: 36760
final_rank: 6

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 105
#define SIZE2 10005

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
		X = 0;
		Y = 0;
	}

	Point(){
		x = y = 0.0;
		X = Y = 0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{
		return x != p.x? x < p.x: y < p.y;
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}

   	/*
	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/

	double x,y;
	int X,Y;
};

typedef Point Vector;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};



struct Edge{
	Edge(int arg_to,double arg_dist){
		to = arg_to;
		dist = arg_dist;
	}
	int to;
	double dist;
};

struct State{
	State(int arg_node_id,double arg_sum_dist){
		node_id = arg_node_id;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct State &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int node_id;
	double sum_dist;
};

struct Info2{
	Info2(){

		loc[0] = loc[1] = 0;
		sum_dist = 0;
	}
	Info2(int arg_loc0,int arg_loc1,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info2 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}

	int loc[2];
	double sum_dist;
};

struct Info3{
	Info3(){

		loc[0] = loc[1] = loc[2] = 0;
		sum_dist = 0;
	}
	Info3(int arg_loc0,int arg_loc1,int arg_loc2,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		loc[2] = arg_loc2;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info3 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int loc[3];
	double sum_dist;
};

struct TWO{
	TWO(int arg_left,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_right;
	}
	int pos[2];
};

struct THREE{
	THREE(int arg_left,int arg_mid,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_mid;
		pos[2] = arg_right;
	}
	int pos[3];
};

struct Data{
	Data(int arg_p_id,int arg_loc_id){
		p_id = arg_p_id;
		loc_id = arg_loc_id;
	}
	bool operator<(const struct Data &arg) const{

		return p_id < arg.p_id;
	}

	int p_id,loc_id;
};


int N,num_dog;
int first_S[3],first_T[3];
int S[3],T[3];
int boss[SIZE],height[SIZE];
int L[SIZE],R[SIZE];
int work_L[3],work_R[3];
int num_point;
int min_Y,max_Y;
int ans_Y[3];
double D;
double dp[SIZE],dp2[SIZE][SIZE],dp3[SIZE][SIZE][SIZE];
double min_dist[SIZE][SIZE];
Point input[SIZE],point[SIZE];
vector<Point> P[SIZE2];
vector<Edge> G[SIZE];



int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		L[boss_y] = min(L[boss_y],L[boss_x]);
		R[boss_y] = max(R[boss_y],R[boss_x]);
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);

		boss[boss_y] = boss_x;
		height[x]++;
	}
}


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

void func1(){

	for(int i = 0; i < num_point; i++){

		dp[i] = BIG_NUM;
	}

	dp[S[0]] = 0;
	priority_queue<State> Q;

	Q.push(State(S[0],0));

	int next_node;
	double next_dist;

	while(!Q.empty()){

		if(Q.top().sum_dist > dp[Q.top().node_id]+EPS){

			Q.pop();
		}else if(Q.top().node_id == T[0]){

			printf("%.10lf\n",Q.top().sum_dist);
			return;

		}else{

			for(int i = 0; i < G[Q.top().node_id].size(); i++){

				next_node = G[Q.top().node_id][i].to;
				next_dist = Q.top().sum_dist+G[Q.top().node_id][i].dist;

				if(dp[next_node] > next_dist+EPS){
					dp[next_node] = next_dist;
					Q.push(State(next_node,next_dist));
				}
			}
			Q.pop();
		}
	}

	printf("-1\n");
}

vector<TWO> calc_pos2(int first_left,int first_right){

	vector<TWO> ret;
	int group_id = get_boss(first_left);

	for(int l = L[group_id]; l < first_right; l++){
		for(int r = max(l,first_left)+1; r <= R[group_id]; r++){

			ret.push_back(TWO(l,r));
		}
	}

	return ret;
}

vector<THREE> calc_pos3(int first_left,int first_mid,int first_right){

	vector<THREE> ret;
	int group_id = get_boss(first_left);

	for(int l = max(L[group_id],work_L[0]); l <= min(work_R[0],first_mid-1); l++){
		for(int m = max(max(l,first_left)+1,work_L[1]); m <= min(work_R[1],first_right-1); m++){
			for(int r = max(max(m,first_mid)+1,work_L[2]); r <= min(work_R[2],R[group_id]); r++){

				ret.push_back(THREE(l,m,r));
			}
		}
	}

	return ret;
}

void func2(){

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){
			dp2[i][k] = BIG_NUM;
		}
	}

	dp2[S[0]][S[1]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info2> Q[2];
	Q[CURRENT].push(Info2(S[0],S[1],0));

	bool STOP[2] = {false,false};
	bool used[2];

	int num_stop = 0;

	while(true){

		used[0] = false;
		used[1] = false;

		while(!Q[CURRENT].empty()){

			Info2 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			if(info.sum_dist > dp2[info.loc[0]][info.loc[1]]+EPS){

				continue;

			}else{

				if(num_stop == 1 || (num_stop == 0 &&get_boss(info.loc[0]) != get_boss(info.loc[1]))){

					if((STOP[1]) || (!STOP[0] && point[info.loc[0]].Y <= point[info.loc[1]].Y)){

						used[0] = true;

						for(int i = 0; i < G[info.loc[0]].size(); i++){

							int next_node = G[info.loc[0]][i].to;
							if(point[next_node].Y > ans_Y[0] || next_node == info.loc[1])continue;
							double next_dist = info.sum_dist+G[info.loc[0]][i].dist;

							if(dp2[next_node][info.loc[1]] > next_dist+EPS){
								dp2[next_node][info.loc[1]] = next_dist;
								Q[NEXT].push(Info2(next_node,info.loc[1],next_dist));
							}
						}

					}else{

						used[1] = true;

						for(int i = 0; i < G[info.loc[1]].size(); i++){

							int next_node = G[info.loc[1]][i].to;
							if(point[next_node].Y > ans_Y[1] || next_node == info.loc[0])continue;
							double next_dist = info.sum_dist+G[info.loc[1]][i].dist;

							if(dp2[info.loc[0]][next_node] > next_dist+EPS){
								dp2[info.loc[0]][next_node] = next_dist;
								Q[NEXT].push(Info2(info.loc[0],next_node,next_dist));
							}
						}
					}

				}else{ //同グループ

					used[0] = true;
					used[1] = true;

					vector<TWO> vec = calc_pos2(min(info.loc[0],info.loc[1]),max(info.loc[0],info.loc[1]));

					int next0,next1,dist0,dist1;

					for(int i = 0; i < vec.size(); i++){

						if(info.loc[0] < info.loc[1]){ //index順とXの大小は一致している

							next0 = vec[i].pos[0];
							next1 = vec[i].pos[1];

						}else{

							next0 = vec[i].pos[1];
							next1 = vec[i].pos[0];
						}

						dist0 = min_dist[info.loc[0]][next0];
						dist1 = min_dist[info.loc[1]][next1];

						double next_dist = info.sum_dist+dist0+dist1;


						if(dp2[next0][next1] > next_dist+EPS){
							dp2[next0][next1] = next_dist;
							//★★PQには突っ込まない★★
						}else if(fabs(dp2[next0][next1]-next_dist) < EPS){

							//★初期位置から動かず★

						}else{

							continue; //★★注意★★
						}

						int to_0,to_1;

						for(int a = 0; a < G[next0].size(); a++){

							to_0 = G[next0][a].to;
							if(point[info.loc[0]].Y == point[to_0].Y)continue;
							if(point[to_0].Y > ans_Y[0])continue;
							for(int b = 0; b < G[next1].size(); b++){
								to_1 = G[next1][b].to;
								if(point[info.loc[1]].Y == point[to_1].Y)continue;
								if(to_1 == to_0)continue;
								if(point[to_1].Y > ans_Y[1])continue;

								double tmp_dist = next_dist+G[next0][a].dist+G[next1][b].dist;
								if(dp2[to_0][to_1] > tmp_dist+EPS){
									dp2[to_0][to_1] = tmp_dist;
									Q[NEXT].push(Info2(to_0,to_1,tmp_dist));
								}
							}
						}
					}
				}
			}
		}

		if(Q[NEXT].size() == 0){
			if(!STOP[0] && used[0]){
				STOP[0] = true;
				num_stop++;
			}
			if(!STOP[1] && used[1]){
				STOP[1] = true;
				num_stop++;
			}

			if(num_stop == 2){

				break;
			}else{

				if(STOP[0]){

					for(int i = 0; i < num_point; i++){

						if(fabs(dp2[T[0]][i]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info2(T[0],i,dp2[T[0]][i]));
					}

				}else{

					for(int i = 0; i < num_point; i++){

						if(fabs(dp2[i][T[1]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info2(i,T[1],dp2[i][T[1]]));
					}
				}

				if(Q[NEXT].size() == 0){

					break;
				}
			}
		}

		swap(CURRENT,NEXT);
	}

	if(fabs(dp2[T[0]][T[1]]-BIG_NUM) < EPS){

		printf("-1\n");

	}else{

		printf("%.10lf\n",dp2[T[0]][T[1]]);
	}
}

void func3(){

	for(int a = 0; a < num_point; a++){
		for(int b = 0; b < num_point; b++){
			for(int c = 0; c < num_point; c++){

				dp3[a][b][c] = BIG_NUM;
			}
		}
	}

	dp3[S[0]][S[1]][S[2]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info3> Q[2];
	Q[CURRENT].push(Info3(S[0],S[1],S[2],0));

	int num_stop = 0;
	bool STOP[3] = {false,false,false};
	bool used[3];

	while(true){

		//printf("num_stop:%d\n",num_stop);

		for(int i = 0; i < 3; i++){

			used[i] = false;
		}

		while(!Q[CURRENT].empty()){

			Info3 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			int minimum = BIG_NUM;
			int num_minimum = 0;
			int max_index = -1;

			for(int i = 0; i < 3; i++){

				if(STOP[i])continue;

				if(minimum > point[info.loc[i]].Y){
					minimum = point[info.loc[i]].Y;
					num_minimum = 1;
				}else if(minimum == point[info.loc[i]].Y){

					num_minimum++;
				}else{

					max_index = i;
				}
			}

			bool sameFLG = false;
			if(num_stop == 1){

				if(STOP[0]){

					if(get_boss(info.loc[1]) == get_boss(info.loc[2])){

						sameFLG = true;
					}

				}else if(STOP[1]){

					if(get_boss(info.loc[0]) == get_boss(info.loc[2])){

						sameFLG = true;
					}

				}else{

					if(get_boss(info.loc[1]) == get_boss(info.loc[2])){

						sameFLG = true;
					}
				}
			}

			if((num_minimum == 1) || (num_stop == 1 && !sameFLG) || (num_stop == 0 && get_boss(info.loc[0]) != get_boss(info.loc[1]) &&
					get_boss(info.loc[0]) != get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) != get_boss(info.loc[2]))){ //Yの最小値が1つ、または全てのグループが異なる

				int min_index;

				for(int i = 0; i < 3; i++){
					if(STOP[i])continue;

					if(point[info.loc[i]].Y == minimum){
						min_index = i;
						break;
					}
				}

				//動くのは一匹だけ

				int next[3];
				for(int k = 0; k < 3; k++){

					next[k] = info.loc[k];
				}

				used[min_index] = true;

				for(int i = 0; i < G[info.loc[min_index]].size(); i++){

					int next_node = G[info.loc[min_index]][i].to;
					if(next_node == info.loc[0] || next_node == info.loc[1] || next_node == info.loc[2])continue;
					if(point[next_node].Y > ans_Y[min_index])continue;

					double next_dist = info.sum_dist+G[info.loc[min_index]][i].dist;

					next[min_index] = next_node;

					if(dp3[next[0]][next[1]][next[2]] > next_dist+EPS){

						dp3[next[0]][next[1]][next[2]] = next_dist;
						Q[NEXT].push(Info3(next[0],next[1],next[2],next_dist));
					}
				}

			}else if(num_stop == 0 && get_boss(info.loc[0]) == get_boss(info.loc[1]) && get_boss(info.loc[0]) == get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) == get_boss(info.loc[2])){ //全てのグループが同じ

				//printf("全てのグループが同じ\n");
				//printf("L:%d R:%d\n",L[get_boss(info.loc[0])],R[get_boss(info.loc[0])]);
				//return;

				used[0] = true;
				used[1] = true;
				used[2] = true;

				vector<Data> data;
				for(int i = 0; i < 3; i++){

					data.push_back(Data(info.loc[i],i));
					work_L[i] = -1;
					work_R[i] = BIG_NUM;
				}

				sort(data.begin(),data.end());

				for(int i = 0; i < 3; i++){

					if(point[info.loc[data[i].loc_id]].Y == ans_Y[data[i].loc_id]){

						work_L[i] = T[data[i].loc_id];
						work_R[i] = T[data[i].loc_id];
					}
				}

				/*for(int i = 0; i < 3; i++){

					printf("p_id[%d]:%d\n",i,data[i].p_id);
				}*/

				//printf("L:%d R:%d\n",L[get_boss(data[0].p_id)],R[get_boss(data[0].p_id)]);

				vector<THREE> vec = calc_pos3(data[0].p_id,data[1].p_id,data[2].p_id);

				//printf("vec.size():%lld\n",vec.size());

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < vec.size(); i++){

					//printf("\ni:%d\n",i);

					for(int k = 0; k < 3; k++){

						TMP[data[k].loc_id] = vec[i].pos[k];
						tmp_d[data[k].loc_id] = min_dist[info.loc[data[k].loc_id]][TMP[data[k].loc_id]];
					}

					/*for(int k = 0; k < 3; k++){

						printf("TMP[%d]:%d\n",k,TMP[k]);
						printf("dist:%.3lf\n",tmp_d[k]);
					}*/

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

						//printf("最小値更新\n");

					}else if(fabs(dp3[TMP[0]][TMP[1]][TMP[2]]-next_dist) < EPS){

						//★初期位置から動かず★
						//printf("動かず\n");

					}else{

						//printf("不適\n");
						continue; //★★
					}

					int to_0,to_1,to_2;

					ll debug = 0;

					for(int a = 0; a < G[TMP[0]].size(); a++){
						to_0 = G[TMP[0]][a].to;
						if(point[to_0].Y == point[info.loc[0]].Y)continue;
						if(point[to_0].Y > ans_Y[0])continue;
						for(int b = 0; b < G[TMP[1]].size(); b++){
							to_1 = G[TMP[1]][b].to;
							if(point[to_1].Y == point[info.loc[1]].Y)continue;
							if(point[to_1].Y > ans_Y[1])continue;
							if(to_1 == to_0)continue;
							for(int c = 0; c < G[TMP[2]].size(); c++){
								to_2 = G[TMP[2]][c].to;
								if(point[to_2].Y == point[info.loc[2]].Y)continue;
								if(point[to_2].Y > ans_Y[2])continue;
								if(to_2 == to_0 || to_2 == to_1)continue;

								double tmp_dist = next_dist+G[TMP[0]][a].dist+G[TMP[1]][b].dist+G[TMP[2]][c].dist;

								if(dp3[to_0][to_1][to_2] > tmp_dist+EPS){
									debug++;
									dp3[to_0][to_1][to_2] = tmp_dist;
									Q[NEXT].push(Info3(to_0,to_1,to_2,tmp_dist));
								}
							}
						}
					}
				}

				/*printf("Q[CURRENT].size():%lld Q[NEXT].size():%lld\n",Q[CURRENT].size(),Q[NEXT].size());
				return;*/

			}else{ //グループが1匹+2匹で、2匹が下方,または1匹がストップ

				vector<Data> tmp_v;
				for(int i = 0; i < 3; i++){
					if(STOP[i])continue;
					if(point[info.loc[i]].Y == minimum){

						tmp_v.push_back(Data(info.loc[i],i));
						used[i] = true;
					}
				}

				sort(tmp_v.begin(),tmp_v.end());

				vector<TWO> vec = calc_pos2(tmp_v[0].p_id,tmp_v[1].p_id);

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < 3; i++){
					TMP[i] = info.loc[i];
					tmp_d[i] = 0;
				}

				for(int i = 0; i < vec.size(); i++){

					for(int k = 0; k < 2; k++){

						TMP[tmp_v[k].loc_id] = vec[i].pos[k];
						tmp_d[tmp_v[k].loc_id] = min_dist[info.loc[tmp_v[k].loc_id]][TMP[tmp_v[k].loc_id]];
					}

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

					}else if(fabs(dp3[TMP[0]][TMP[1]][TMP[2]]-next_dist) < EPS){

						//★初期位置から動かず★

					}else{

						continue; //★★
					}

					int to[3];
					for(int a = 0; a < 3; a++){

						to[a] = TMP[a];
					}

					for(int a = 0; a < G[tmp_v[0].loc_id].size(); a++){
						to[tmp_v[0].loc_id] = G[tmp_v[0].loc_id][a].to;
						if(point[to[tmp_v[0].loc_id]].Y == minimum)continue;
						if(point[to[tmp_v[0].loc_id]].Y > ans_Y[tmp_v[0].loc_id])continue;
						if(to[tmp_v[0].loc_id] == max_index)continue;

						for(int b = 0; b < G[tmp_v[1].loc_id].size(); b++){
							to[tmp_v[1].loc_id] = G[tmp_v[1].loc_id][b].to;
							if(point[to[tmp_v[1].loc_id]].Y == minimum)continue;
							if(point[to[tmp_v[1].loc_id]].Y > ans_Y[tmp_v[1].loc_id])continue;
							if(to[tmp_v[1].loc_id] == max_index || to[tmp_v[1].loc_id] == to[tmp_v[0].loc_id])continue;

							double tmp_dist = next_dist+G[tmp_v[0].loc_id][a].dist+G[tmp_v[1].loc_id][b].dist;

							if(dp3[to[0]][to[1]][to[2]] > tmp_dist+EPS){

								dp3[to[0]][to[1]][to[2]] = tmp_dist;
								Q[NEXT].push(Info3(to[0],to[1],to[2],tmp_dist));
							}
						}
					}
				}
			}
		}

		/*printf("Q[NEXT].size():%lld num_stop:%d\n",Q[NEXT].size(),num_stop);
							break;*/

		if(Q[NEXT].size() == 0){
			if(!STOP[0] && used[0]){
				STOP[0] = true;
				num_stop++;
			}
			if(!STOP[1] && used[1]){
				STOP[1] = true;
				num_stop++;
			}
			if(!STOP[2] && used[2]){
				STOP[2] = true;
				num_stop++;
			}
			if(num_stop == 3){

				break;
			}

			if(num_stop == 1){

				for(int i = 0; i < num_point; i++){
					for(int k = 0; k < num_point; k++){

						if(STOP[0]){

							if(fabs(dp3[T[0]][i][k]-BIG_NUM) < EPS){

								continue;
							}
							Q[NEXT].push(Info3(T[0],i,k,dp3[T[0]][i][k]));

						}else if(STOP[1]){

							if(fabs(dp3[i][T[1]][k]-BIG_NUM) < EPS){

								continue;
							}
							Q[NEXT].push(Info3(i,T[1],k,dp3[i][T[1]][k]));


						}else{ //STOP[2]

							if(fabs(dp3[i][k][T[2]]-BIG_NUM) < EPS)continue;

							Q[NEXT].push(Info3(i,k,T[2],dp3[i][k][T[2]]));
						}
					}
				}

			}else{ //num_stop == 2

				for(int i = 0; i < num_point; i++){

					if(!STOP[0]){

						if(fabs(dp3[i][T[1]][T[2]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(i,T[1],T[2],dp3[i][T[1]][T[2]]));

					}else if(!STOP[1]){

						if(fabs(dp3[T[0]][i][T[2]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(T[0],i,T[2],dp3[T[0]][i][T[2]]));

					}else{ //!STOP[2]

						if(fabs(dp3[T[0]][T[1]][i]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(T[0],T[1],i,dp3[T[0]][T[1]][i]));
					}
				}
			}

			if(Q[NEXT].size() == 0){

				break;
			}
		}

		swap(CURRENT,NEXT);
	}

	if(fabs(dp3[T[0]][T[1]][T[2]]-BIG_NUM) < EPS){

		printf("-1\n");
	}else{

		printf("%.10lf\n",dp3[T[0]][T[1]][T[2]]);
	}
}

int main(){

	scanf("%d %d",&N,&num_dog);
	scanf("%lf",&D);

	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_S[i]);
		first_S[i]--;
	}
	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_T[i]);
		first_T[i]--;
	}

	min_Y = BIG_NUM,max_Y = -BIG_NUM;

	for(int i = 0; i < N; i++){

		scanf("%d %d",&input[i].X,&input[i].Y);
		input[i].x = input[i].X;
		input[i].y = input[i].Y;

		min_Y = min(min_Y,input[i].Y);
		max_Y = max(max_Y,input[i].Y);

		P[input[i].Y].push_back(input[i]);
	}

	num_point = 0;

	for(int i = min_Y; i <= max_Y; i++){
		if(P[i].size() == 0)continue;

		sort(P[i].begin(),P[i].end());

		L[i] = num_point;
		point[num_point++] = P[i][0];

		for(int k = 1; k < P[i].size(); k++){

			R[i] = num_point;
			point[num_point++] = P[i][k];
		}
	}

	for(int i = 0; i < num_dog; i++){
		for(int k = 0; k < num_point; k++){
			if(input[first_S[i]] == point[k]){

				S[i] = k;
			}
			if(input[first_T[i]] == point[k]){

				T[i] = k;
			}
		}
	}

	for(int i = 0; i < num_point; i++){

		boss[i] = i;
		height[i] = i;
		L[i] = i;
		R[i] = i;
	}

	for(int i = 0; i < num_dog; i++){

		ans_Y[i] = point[T[i]].Y;
	}

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){

			if(k == i){

				min_dist[i][k] = 0;
			}else{

				min_dist[i][k] = BIG_NUM;
			}
		}
	}

	//エッジ張り
	for(int i = 0; i < num_point-1; i++){
		for(int k = i+1; k < num_point; k++){
			if(calc_dist(point[i],point[k]) > D+EPS)continue;

			bool FLG = true;
			Line tmp_line = Line(point[i],point[k]);
			for(int a = 0; a < num_point; a++){
				if(a == i || a == k)continue;

				if(getDistanceSP(tmp_line,point[a]) < EPS){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			if(point[i].Y == point[k].Y){

				unite(i,k);
				double tmp_dist = calc_dist(point[i],point[k]);
				G[i].push_back(Edge(k,tmp_dist));
				G[k].push_back(Edge(i,tmp_dist));

				min_dist[i][k] = tmp_dist;
				min_dist[k][i] = tmp_dist;
				//printf("%d-%dにエッジを張った\n",i,k);

			}else{

				int from = i;
				int to = k;
				if(point[i].Y > point[k].Y){

					swap(from,to);
				}
				G[from].push_back(Edge(to,calc_dist(point[i],point[k])));
				//printf("%d-%dにエッジを張った\n",from,to);
			}
		}
	}

	for(int mid = 0; mid < num_point; mid++){
		for(int start = 0; start < num_point; start++){
			if(fabs(min_dist[start][mid]-BIG_NUM) < EPS)continue;
			for(int goal = 0; goal < num_point; goal++){
				if(fabs(min_dist[mid][goal]-BIG_NUM) < EPS)continue;

				min_dist[start][goal] = min(min_dist[start][goal],min_dist[start][mid]+min_dist[mid][goal]);
			}
		}
	}

	if(num_dog == 1){

		func1();

	}else if(num_dog == 2){

		func2();

	}else{

		func3();
	}

	return 0;
}
accuracy: 0.6428571428571429
time_ms: 630
memory_kb: 36728
final_rank: 10

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 105
#define SIZE2 10005

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
		X = 0;
		Y = 0;
	}

	Point(){
		x = y = 0.0;
		X = Y = 0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{
		return x != p.x? x < p.x: y < p.y;
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}

   	/*
	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/

	double x,y;
	int X,Y;
};

typedef Point Vector;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};



struct Edge{
	Edge(int arg_to,double arg_dist){
		to = arg_to;
		dist = arg_dist;
	}
	int to;
	double dist;
};

struct State{
	State(int arg_node_id,double arg_sum_dist){
		node_id = arg_node_id;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct State &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int node_id;
	double sum_dist;
};

struct Info2{
	Info2(){

		loc[0] = loc[1] = 0;
		sum_dist = 0;
	}
	Info2(int arg_loc0,int arg_loc1,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info2 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}

	int loc[2];
	double sum_dist;
};

struct Info3{
	Info3(){

		loc[0] = loc[1] = loc[2] = 0;
		sum_dist = 0;
	}
	Info3(int arg_loc0,int arg_loc1,int arg_loc2,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		loc[2] = arg_loc2;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info3 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int loc[3];
	double sum_dist;
};

struct TWO{
	TWO(int arg_left,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_right;
	}
	int pos[2];
};

struct THREE{
	THREE(int arg_left,int arg_mid,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_mid;
		pos[2] = arg_right;
	}
	int pos[3];
};

struct Data{
	Data(int arg_p_id,int arg_loc_id){
		p_id = arg_p_id;
		loc_id = arg_loc_id;
	}
	bool operator<(const struct Data &arg) const{

		return p_id < arg.p_id;
	}

	int p_id,loc_id;
};


int N,num_dog;
int first_S[3],first_T[3];
int S[3],T[3];
int boss[SIZE],height[SIZE];
int L[SIZE],R[SIZE];
int work_L[3],work_R[3];
int num_point;
int min_Y,max_Y;
int ans_Y[3];
double D;
double dp[SIZE],dp2[SIZE][SIZE],dp3[SIZE][SIZE][SIZE];
double min_dist[SIZE][SIZE];
Point input[SIZE],point[SIZE];
vector<Point> P[SIZE2];
vector<Edge> G[SIZE];



int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		L[boss_y] = min(L[boss_y],L[boss_x]);
		R[boss_y] = max(R[boss_y],R[boss_x]);
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);

		boss[boss_y] = boss_x;
		height[x]++;
	}
}


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

void func1(){

	for(int i = 0; i < num_point; i++){

		dp[i] = BIG_NUM;
	}

	dp[S[0]] = 0;
	priority_queue<State> Q;

	Q.push(State(S[0],0));

	int next_node;
	double next_dist;

	while(!Q.empty()){

		if(Q.top().sum_dist > dp[Q.top().node_id]+EPS){

			Q.pop();
		}else if(Q.top().node_id == T[0]){

			printf("%.10lf\n",Q.top().sum_dist);
			return;

		}else{

			for(int i = 0; i < G[Q.top().node_id].size(); i++){

				next_node = G[Q.top().node_id][i].to;
				next_dist = Q.top().sum_dist+G[Q.top().node_id][i].dist;

				if(dp[next_node] > next_dist+EPS){
					dp[next_node] = next_dist;
					Q.push(State(next_node,next_dist));
				}
			}
			Q.pop();
		}
	}

	printf("-1\n");
}

vector<TWO> calc_pos2(int first_left,int first_right){

	vector<TWO> ret;
	int group_id = get_boss(first_left);

	for(int l = L[group_id]; l < first_right; l++){
		for(int r = max(l,first_left)+1; r <= R[group_id]; r++){

			ret.push_back(TWO(l,r));
		}
	}

	return ret;
}

vector<THREE> calc_pos3(int first_left,int first_mid,int first_right){

	vector<THREE> ret;
	int group_id = get_boss(first_left);

	for(int l = max(L[group_id],work_L[0]); l <= min(work_R[0],first_mid-1); l++){
		for(int m = max(max(l,first_left)+1,work_L[1]); m <= min(work_R[1],first_right-1); m++){
			for(int r = max(max(m,first_mid)+1,work_L[2]); r <= min(work_R[2],R[group_id]); r++){

				ret.push_back(THREE(l,m,r));
			}
		}
	}

	return ret;
}

void func2(){

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){
			dp2[i][k] = BIG_NUM;
		}
	}

	dp2[S[0]][S[1]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info2> Q[2];
	Q[CURRENT].push(Info2(S[0],S[1],0));

	bool STOP[2] = {false,false};
	bool used[2];

	int num_stop = 0;

	while(true){

		used[0] = false;
		used[1] = false;

		while(!Q[CURRENT].empty()){

			Info2 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			if(info.sum_dist > dp2[info.loc[0]][info.loc[1]]+EPS){

				continue;

			}else{

				if(num_stop == 1 || get_boss(info.loc[0]) != get_boss(info.loc[1])){

					if((STOP[1]) || (!STOP[0] && point[info.loc[0]].Y <= point[info.loc[1]].Y)){

						used[0] = true;

						for(int i = 0; i < G[info.loc[0]].size(); i++){

							int next_node = G[info.loc[0]][i].to;
							if(point[next_node].Y > ans_Y[0] || next_node == info.loc[1])continue;
							double next_dist = info.sum_dist+G[info.loc[0]][i].dist;

							if(dp2[next_node][info.loc[1]] > next_dist+EPS){
								dp2[next_node][info.loc[1]] = next_dist;
								Q[NEXT].push(Info2(next_node,info.loc[1],next_dist));
							}
						}

					}else{

						used[1] = true;

						for(int i = 0; i < G[info.loc[1]].size(); i++){

							int next_node = G[info.loc[1]][i].to;
							if(point[next_node].Y > ans_Y[1] || next_node == info.loc[0])continue;
							double next_dist = info.sum_dist+G[info.loc[1]][i].dist;

							if(dp2[info.loc[0]][next_node] > next_dist+EPS){
								dp2[info.loc[0]][next_node] = next_dist;
								Q[NEXT].push(Info2(info.loc[0],next_node,next_dist));
							}
						}
					}

				}else{ //同グループ

					used[0] = true;
					used[1] = true;

					vector<TWO> vec = calc_pos2(min(info.loc[0],info.loc[1]),max(info.loc[0],info.loc[1]));

					int next0,next1,dist0,dist1;

					for(int i = 0; i < vec.size(); i++){

						if(info.loc[0] < info.loc[1]){ //index順とXの大小は一致している

							next0 = vec[i].pos[0];
							next1 = vec[i].pos[1];

						}else{

							next0 = vec[i].pos[1];
							next1 = vec[i].pos[0];
						}

						dist0 = min_dist[info.loc[0]][next0];
						dist1 = min_dist[info.loc[1]][next1];

						double next_dist = info.sum_dist+dist0+dist1;


						if(dp2[next0][next1] > next_dist+EPS){
							dp2[next0][next1] = next_dist;
							//★★PQには突っ込まない★★
						}else if(fabs(dp2[next0][next1]-next_dist) < EPS){

							//★初期位置から動かず★

						}else{

							continue; //★★注意★★
						}

						int to_0,to_1;

						for(int a = 0; a < G[next0].size(); a++){

							to_0 = G[next0][a].to;
							if(point[info.loc[0]].Y == point[to_0].Y)continue;
							if(point[to_0].Y > ans_Y[0])continue;
							for(int b = 0; b < G[next1].size(); b++){
								to_1 = G[next1][b].to;
								if(point[info.loc[1]].Y == point[to_1].Y)continue;
								if(to_1 == to_0)continue;
								if(point[to_1].Y > ans_Y[1])continue;

								double tmp_dist = next_dist+G[next0][a].dist+G[next1][b].dist;
								if(dp2[to_0][to_1] > tmp_dist+EPS){
									dp2[to_0][to_1] = tmp_dist;
									Q[NEXT].push(Info2(to_0,to_1,tmp_dist));
								}
							}
						}
					}
				}
			}
		}

		if(Q[NEXT].size() == 0){
			if(!STOP[0] && used[0]){
				STOP[0] = true;
				num_stop++;
			}
			if(!STOP[1] && used[1]){
				STOP[1] = true;
				num_stop++;
			}

			if(num_stop == 2){

				break;
			}else{

				if(STOP[0]){

					for(int i = 0; i < num_point; i++){

						if(fabs(dp2[T[0]][i]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info2(T[0],i,dp2[T[0]][i]));
					}

				}else{

					for(int i = 0; i < num_point; i++){

						if(fabs(dp2[i][T[1]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info2(i,T[1],dp2[i][T[1]]));
					}
				}

				if(Q[NEXT].size() == 0){

					break;
				}
			}
		}

		swap(CURRENT,NEXT);
	}

	if(fabs(dp2[T[0]][T[1]]-BIG_NUM) < EPS){

		printf("-1\n");

	}else{

		printf("%.10lf\n",dp2[T[0]][T[1]]);
	}
}

void func3(){

	for(int a = 0; a < num_point; a++){
		for(int b = 0; b < num_point; b++){
			for(int c = 0; c < num_point; c++){

				dp3[a][b][c] = BIG_NUM;
			}
		}
	}

	dp3[S[0]][S[1]][S[2]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info3> Q[2];
	Q[CURRENT].push(Info3(S[0],S[1],S[2],0));

	int num_stop = 0;
	bool STOP[3] = {false,false,false};
	bool used[3];

	while(true){

		//printf("num_stop:%d\n",num_stop);

		for(int i = 0; i < 3; i++){

			used[i] = false;
		}

		while(!Q[CURRENT].empty()){

			Info3 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			int minimum = BIG_NUM;
			int num_minimum = 0;
			int max_index = -1;

			for(int i = 0; i < 3; i++){

				if(STOP[i])continue;

				if(minimum > point[info.loc[i]].Y){
					minimum = point[info.loc[i]].Y;
					num_minimum = 1;
				}else if(minimum == point[info.loc[i]].Y){

					num_minimum++;
				}else{

					max_index = i;
				}
			}

			bool sameFLG = false;
			if(num_stop == 1){

				if(STOP[0]){

					if(get_boss(info.loc[1]) == get_boss(info.loc[2])){

						sameFLG = true;
					}

				}else if(STOP[1]){

					if(get_boss(info.loc[0]) == get_boss(info.loc[2])){

						sameFLG = true;
					}

				}else{

					if(get_boss(info.loc[1]) == get_boss(info.loc[2])){

						sameFLG = true;
					}
				}
			}

			if((num_minimum == 1) || (num_stop == 1 && !sameFLG) || (num_stop == 0 && get_boss(info.loc[0]) != get_boss(info.loc[1]) &&
					get_boss(info.loc[0]) != get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) != get_boss(info.loc[2]))){ //Yの最小値が1つ、または全てのグループが異なる

				int min_index;

				for(int i = 0; i < 3; i++){
					if(STOP[i])continue;

					if(point[info.loc[i]].Y == minimum){
						min_index = i;
						break;
					}
				}

				//動くのは一匹だけ

				int next[3];
				for(int k = 0; k < 3; k++){

					next[k] = info.loc[k];
				}

				used[min_index] = true;

				for(int i = 0; i < G[info.loc[min_index]].size(); i++){

					int next_node = G[info.loc[min_index]][i].to;
					if(next_node == info.loc[0] || next_node == info.loc[1] || next_node == info.loc[2])continue;
					if(point[next_node].Y > ans_Y[min_index])continue;

					double next_dist = info.sum_dist+G[info.loc[min_index]][i].dist;

					next[min_index] = next_node;

					if(dp3[next[0]][next[1]][next[2]] > next_dist+EPS){

						dp3[next[0]][next[1]][next[2]] = next_dist;
						Q[NEXT].push(Info3(next[0],next[1],next[2],next_dist));
					}
				}

			}else if(num_stop == 0 && get_boss(info.loc[0]) == get_boss(info.loc[1]) && get_boss(info.loc[0]) == get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) == get_boss(info.loc[2])){ //全てのグループが同じ

				//printf("全てのグループが同じ\n");
				//printf("L:%d R:%d\n",L[get_boss(info.loc[0])],R[get_boss(info.loc[0])]);
				//return;

				used[0] = true;
				used[1] = true;
				used[2] = true;

				vector<Data> data;
				for(int i = 0; i < 3; i++){

					data.push_back(Data(info.loc[i],i));
					work_L[i] = -1;
					work_R[i] = BIG_NUM;
				}

				sort(data.begin(),data.end());

				for(int i = 0; i < 3; i++){

					if(point[info.loc[data[i].loc_id]].Y == ans_Y[data[i].loc_id]){

						work_L[i] = T[data[i].loc_id];
						work_R[i] = T[data[i].loc_id];
					}
				}

				/*for(int i = 0; i < 3; i++){

					printf("p_id[%d]:%d\n",i,data[i].p_id);
				}*/

				//printf("L:%d R:%d\n",L[get_boss(data[0].p_id)],R[get_boss(data[0].p_id)]);

				vector<THREE> vec = calc_pos3(data[0].p_id,data[1].p_id,data[2].p_id);

				//printf("vec.size():%lld\n",vec.size());

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < vec.size(); i++){

					//printf("\ni:%d\n",i);

					for(int k = 0; k < 3; k++){

						TMP[data[k].loc_id] = vec[i].pos[k];
						tmp_d[data[k].loc_id] = min_dist[info.loc[data[k].loc_id]][TMP[data[k].loc_id]];
					}

					/*for(int k = 0; k < 3; k++){

						printf("TMP[%d]:%d\n",k,TMP[k]);
						printf("dist:%.3lf\n",tmp_d[k]);
					}*/

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

						//printf("最小値更新\n");

					}else if(fabs(dp3[TMP[0]][TMP[1]][TMP[2]]-next_dist) < EPS){

						//★初期位置から動かず★
						//printf("動かず\n");

					}else{

						//printf("不適\n");
						continue; //★★
					}

					int to_0,to_1,to_2;

					ll debug = 0;

					for(int a = 0; a < G[TMP[0]].size(); a++){
						to_0 = G[TMP[0]][a].to;
						if(point[to_0].Y == point[info.loc[0]].Y)continue;
						if(point[to_0].Y > ans_Y[0])continue;
						for(int b = 0; b < G[TMP[1]].size(); b++){
							to_1 = G[TMP[1]][b].to;
							if(point[to_1].Y == point[info.loc[1]].Y)continue;
							if(point[to_1].Y > ans_Y[1])continue;
							if(to_1 == to_0)continue;
							for(int c = 0; c < G[TMP[2]].size(); c++){
								to_2 = G[TMP[2]][c].to;
								if(point[to_2].Y == point[info.loc[2]].Y)continue;
								if(point[to_2].Y > ans_Y[2])continue;
								if(to_2 == to_0 || to_2 == to_1)continue;

								double tmp_dist = next_dist+G[TMP[0]][a].dist+G[TMP[1]][b].dist+G[TMP[2]][c].dist;

								if(dp3[to_0][to_1][to_2] > tmp_dist+EPS){
									debug++;
									dp3[to_0][to_1][to_2] = tmp_dist;
									Q[NEXT].push(Info3(to_0,to_1,to_2,tmp_dist));
								}
							}
						}
					}
				}

				/*printf("Q[CURRENT].size():%lld Q[NEXT].size():%lld\n",Q[CURRENT].size(),Q[NEXT].size());
				return;*/

			}else{ //グループが1匹+2匹で、2匹が下方,または1匹がストップ

				vector<Data> tmp_v;
				for(int i = 0; i < 3; i++){
					if(STOP[i])continue;
					if(point[info.loc[i]].Y == minimum){

						tmp_v.push_back(Data(info.loc[i],i));
						used[i] = true;
					}
				}

				sort(tmp_v.begin(),tmp_v.end());

				vector<TWO> vec = calc_pos2(tmp_v[0].p_id,tmp_v[1].p_id);

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < 3; i++){
					TMP[i] = info.loc[i];
					tmp_d[i] = 0;
				}

				for(int i = 0; i < vec.size(); i++){

					for(int k = 0; k < 2; k++){

						TMP[tmp_v[k].loc_id] = vec[i].pos[k];
						tmp_d[tmp_v[k].loc_id] = min_dist[info.loc[tmp_v[k].loc_id]][TMP[tmp_v[k].loc_id]];
					}

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

					}else if(fabs(dp3[TMP[0]][TMP[1]][TMP[2]]-next_dist) < EPS){

						//★初期位置から動かず★

					}else{

						continue; //★★
					}

					int to[3];
					for(int a = 0; a < 3; a++){

						to[a] = TMP[a];
					}

					for(int a = 0; a < G[tmp_v[0].loc_id].size(); a++){
						to[tmp_v[0].loc_id] = G[tmp_v[0].loc_id][a].to;
						if(point[to[tmp_v[0].loc_id]].Y == minimum)continue;
						if(point[to[tmp_v[0].loc_id]].Y > ans_Y[tmp_v[0].loc_id])continue;
						if(to[tmp_v[0].loc_id] == max_index)continue;

						for(int b = 0; b < G[tmp_v[1].loc_id].size(); b++){
							to[tmp_v[1].loc_id] = G[tmp_v[1].loc_id][b].to;
							if(point[to[tmp_v[1].loc_id]].Y == minimum)continue;
							if(point[to[tmp_v[1].loc_id]].Y > ans_Y[tmp_v[1].loc_id])continue;
							if(to[tmp_v[1].loc_id] == max_index || to[tmp_v[1].loc_id] == to[tmp_v[0].loc_id])continue;

							double tmp_dist = next_dist+G[tmp_v[0].loc_id][a].dist+G[tmp_v[1].loc_id][b].dist;

							if(dp3[to[0]][to[1]][to[2]] > tmp_dist+EPS){

								dp3[to[0]][to[1]][to[2]] = tmp_dist;
								Q[NEXT].push(Info3(to[0],to[1],to[2],tmp_dist));
							}
						}
					}
				}
			}
		}

		/*printf("Q[NEXT].size():%lld num_stop:%d\n",Q[NEXT].size(),num_stop);
							break;*/

		if(Q[NEXT].size() == 0){
			if(!STOP[0] && used[0]){
				STOP[0] = true;
				num_stop++;
			}
			if(!STOP[1] && used[1]){
				STOP[1] = true;
				num_stop++;
			}
			if(!STOP[2] && used[2]){
				STOP[2] = true;
				num_stop++;
			}
			if(num_stop == 3){

				break;
			}

			if(num_stop == 1){

				for(int i = 0; i < num_point; i++){
					for(int k = 0; k < num_point; k++){

						if(STOP[0]){

							if(fabs(dp3[T[0]][i][k]-BIG_NUM) < EPS){

								continue;
							}
							Q[NEXT].push(Info3(T[0],i,k,dp3[T[0]][i][k]));

						}else if(STOP[1]){

							if(fabs(dp3[i][T[1]][k]-BIG_NUM) < EPS){

								continue;
							}
							Q[NEXT].push(Info3(i,T[1],k,dp3[i][T[1]][k]));


						}else{ //STOP[2]

							if(fabs(dp3[i][k][T[2]]-BIG_NUM) < EPS)continue;

							Q[NEXT].push(Info3(i,k,T[2],dp3[i][k][T[2]]));
						}
					}
				}

			}else{ //num_stop == 2

				for(int i = 0; i < num_point; i++){

					if(!STOP[0]){

						if(fabs(dp3[i][T[1]][T[2]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(i,T[1],T[2],dp3[i][T[1]][T[2]]));

					}else if(!STOP[1]){

						if(fabs(dp3[T[0]][i][T[2]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(T[0],i,T[2],dp3[T[0]][i][T[2]]));

					}else{ //!STOP[2]

						if(fabs(dp3[T[0]][T[1]][i]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(T[0],T[1],i,dp3[T[0]][T[1]][i]));
					}
				}
			}

			if(Q[NEXT].size() == 0){

				break;
			}
		}

		swap(CURRENT,NEXT);
	}

	if(fabs(dp3[T[0]][T[1]][T[2]]-BIG_NUM) < EPS){

		printf("-1\n");
	}else{

		printf("%.10lf\n",dp3[T[0]][T[1]][T[2]]);
	}
}

int main(){

	scanf("%d %d",&N,&num_dog);
	scanf("%lf",&D);

	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_S[i]);
		first_S[i]--;
	}
	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_T[i]);
		first_T[i]--;
	}

	min_Y = BIG_NUM,max_Y = -BIG_NUM;

	for(int i = 0; i < N; i++){

		scanf("%d %d",&input[i].X,&input[i].Y);
		input[i].x = input[i].X;
		input[i].y = input[i].Y;

		min_Y = min(min_Y,input[i].Y);
		max_Y = max(max_Y,input[i].Y);

		P[input[i].Y].push_back(input[i]);
	}

	num_point = 0;

	for(int i = min_Y; i <= max_Y; i++){
		if(P[i].size() == 0)continue;

		sort(P[i].begin(),P[i].end());

		L[i] = num_point;
		point[num_point++] = P[i][0];

		for(int k = 1; k < P[i].size(); k++){

			R[i] = num_point;
			point[num_point++] = P[i][k];
		}
	}

	for(int i = 0; i < num_dog; i++){
		for(int k = 0; k < num_point; k++){
			if(input[first_S[i]] == point[k]){

				S[i] = k;
			}
			if(input[first_T[i]] == point[k]){

				T[i] = k;
			}
		}
	}

	for(int i = 0; i < num_point; i++){

		boss[i] = i;
		height[i] = i;
		L[i] = i;
		R[i] = i;
	}

	for(int i = 0; i < num_dog; i++){

		ans_Y[i] = point[T[i]].Y;
	}

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){

			if(k == i){

				min_dist[i][k] = 0;
			}else{

				min_dist[i][k] = BIG_NUM;
			}
		}
	}

	//エッジ張り
	for(int i = 0; i < num_point-1; i++){
		for(int k = i+1; k < num_point; k++){
			if(calc_dist(point[i],point[k]) > D+EPS)continue;

			bool FLG = true;
			Line tmp_line = Line(point[i],point[k]);
			for(int a = 0; a < num_point; a++){
				if(a == i || a == k)continue;

				if(getDistanceSP(tmp_line,point[a]) < EPS){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			if(point[i].Y == point[k].Y){

				unite(i,k);
				double tmp_dist = calc_dist(point[i],point[k]);
				G[i].push_back(Edge(k,tmp_dist));
				G[k].push_back(Edge(i,tmp_dist));

				min_dist[i][k] = tmp_dist;
				min_dist[k][i] = tmp_dist;
				//printf("%d-%dにエッジを張った\n",i,k);

			}else{

				int from = i;
				int to = k;
				if(point[i].Y > point[k].Y){

					swap(from,to);
				}
				G[from].push_back(Edge(to,calc_dist(point[i],point[k])));
				//printf("%d-%dにエッジを張った\n",from,to);
			}
		}
	}

	for(int mid = 0; mid < num_point; mid++){
		for(int start = 0; start < num_point; start++){
			if(fabs(min_dist[start][mid]-BIG_NUM) < EPS)continue;
			for(int goal = 0; goal < num_point; goal++){
				if(fabs(min_dist[mid][goal]-BIG_NUM) < EPS)continue;

				min_dist[start][goal] = min(min_dist[start][goal],min_dist[start][mid]+min_dist[mid][goal]);
			}
		}
	}

	if(num_dog == 1){

		func1();

	}else if(num_dog == 2){

		func2();

	}else{

		func3();
	}

	return 0;
}
accuracy: 0.6428571428571429
time_ms: 580
memory_kb: 36788
final_rank: 8

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 105
#define SIZE2 10005

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
		X = 0;
		Y = 0;
	}

	Point(){
		x = y = 0.0;
		X = Y = 0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{
		return x != p.x? x < p.x: y < p.y;
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}

   	/*
	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/

	double x,y;
	int X,Y;
};

typedef Point Vector;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};



struct Edge{
	Edge(int arg_to,double arg_dist){
		to = arg_to;
		dist = arg_dist;
	}
	int to;
	double dist;
};

struct State{
	State(int arg_node_id,double arg_sum_dist){
		node_id = arg_node_id;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct State &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int node_id;
	double sum_dist;
};

struct Info2{
	Info2(){

		loc[0] = loc[1] = 0;
		sum_dist = 0;
	}
	Info2(int arg_loc0,int arg_loc1,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info2 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}

	int loc[2];
	double sum_dist;
};

struct Info3{
	Info3(){

		loc[0] = loc[1] = loc[2] = 0;
		sum_dist = 0;
	}
	Info3(int arg_loc0,int arg_loc1,int arg_loc2,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		loc[2] = arg_loc2;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info3 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int loc[3];
	double sum_dist;
};

struct TWO{
	TWO(int arg_left,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_right;
	}
	int pos[2];
};

struct THREE{
	THREE(int arg_left,int arg_mid,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_mid;
		pos[2] = arg_right;
	}
	int pos[3];
};

struct Data{
	Data(int arg_p_id,int arg_loc_id){
		p_id = arg_p_id;
		loc_id = arg_loc_id;
	}
	bool operator<(const struct Data &arg) const{

		return p_id < arg.p_id;
	}

	int p_id,loc_id;
};


int N,num_dog;
int first_S[3],first_T[3];
int S[3],T[3];
int boss[SIZE],height[SIZE];
int L[SIZE],R[SIZE];
int work_L[3],work_R[3];
int num_point;
int min_Y,max_Y;
int ans_Y[3];
double D;
double dp[SIZE],dp2[SIZE][SIZE],dp3[SIZE][SIZE][SIZE];
double min_dist[SIZE][SIZE];
Point input[SIZE],point[SIZE];
vector<Point> P[SIZE2];
vector<Edge> G[SIZE];



int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		L[boss_y] = min(L[boss_y],L[boss_x]);
		R[boss_y] = max(R[boss_y],R[boss_x]);
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);

		boss[boss_y] = boss_x;
		height[x]++;
	}
}


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

void func1(){

	for(int i = 0; i < num_point; i++){

		dp[i] = BIG_NUM;
	}

	dp[S[0]] = 0;
	priority_queue<State> Q;

	Q.push(State(S[0],0));

	int next_node;
	double next_dist;

	while(!Q.empty()){

		if(Q.top().sum_dist > dp[Q.top().node_id]+EPS){

			Q.pop();
		}else if(Q.top().node_id == T[0]){

			printf("%.10lf\n",Q.top().sum_dist);
			return;

		}else{

			for(int i = 0; i < G[Q.top().node_id].size(); i++){

				next_node = G[Q.top().node_id][i].to;
				next_dist = Q.top().sum_dist+G[Q.top().node_id][i].dist;

				if(dp[next_node] > next_dist+EPS){
					dp[next_node] = next_dist;
					Q.push(State(next_node,next_dist));
				}
			}
			Q.pop();
		}
	}

	printf("-1\n");
}

vector<TWO> calc_pos2(int first_left,int first_right){

	vector<TWO> ret;
	int group_id = get_boss(first_left);

	for(int l = L[group_id]; l < first_right; l++){
		for(int r = max(l,first_left)+1; r <= R[group_id]; r++){

			ret.push_back(TWO(l,r));
		}
	}

	return ret;
}

vector<THREE> calc_pos3(int first_left,int first_mid,int first_right){

	vector<THREE> ret;
	int group_id = get_boss(first_left);

	for(int l = max(L[group_id],work_L[0]); l <= min(work_R[0],first_mid-1); l++){
		for(int m = max(max(l,first_left)+1,work_L[1]); m <= min(work_R[1],first_right-1); m++){
			for(int r = max(max(m,first_mid)+1,work_L[2]); r <= min(work_R[2],R[group_id]); r++){

				ret.push_back(THREE(l,m,r));
			}
		}
	}

	return ret;
}

void func2(){

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){
			dp2[i][k] = BIG_NUM;
		}
	}

	dp2[S[0]][S[1]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info2> Q[2];
	Q[CURRENT].push(Info2(S[0],S[1],0));

	bool STOP[2] = {false,false};
	bool used[2];

	int num_stop = 0;

	while(true){

		used[0] = false;
		used[1] = false;

		while(!Q[CURRENT].empty()){

			Info2 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			if(info.sum_dist > dp2[info.loc[0]][info.loc[1]]+EPS){

				continue;

			}else{

				if(get_boss(info.loc[0]) != get_boss(info.loc[1]) || num_stop == 1){

					if((STOP[1]) || (!STOP[0] && point[info.loc[0]].Y <= point[info.loc[1]].Y)){

						used[0] = true;

						for(int i = 0; i < G[info.loc[0]].size(); i++){

							int next_node = G[info.loc[0]][i].to;
							if(point[next_node].Y > ans_Y[0] || next_node == info.loc[1])continue;
							double next_dist = info.sum_dist+G[info.loc[0]][i].dist;

							if(dp2[next_node][info.loc[1]] > next_dist+EPS){
								dp2[next_node][info.loc[1]] = next_dist;
								Q[NEXT].push(Info2(next_node,info.loc[1],next_dist));
							}
						}

					}else{

						used[1] = true;

						for(int i = 0; i < G[info.loc[1]].size(); i++){

							int next_node = G[info.loc[1]][i].to;
							if(point[next_node].Y > ans_Y[1] || next_node == info.loc[0])continue;
							double next_dist = info.sum_dist+G[info.loc[1]][i].dist;

							if(dp2[info.loc[0]][next_node] > next_dist+EPS){
								dp2[info.loc[0]][next_node] = next_dist;
								Q[NEXT].push(Info2(info.loc[0],next_node,next_dist));
							}
						}
					}

				}else{ //同グループ

					used[0] = true;
					used[1] = true;

					vector<TWO> vec = calc_pos2(min(info.loc[0],info.loc[1]),max(info.loc[0],info.loc[1]));

					int next0,next1,dist0,dist1;

					for(int i = 0; i < vec.size(); i++){

						if(info.loc[0] < info.loc[1]){ //index順とXの大小は一致している

							next0 = vec[i].pos[0];
							next1 = vec[i].pos[1];

						}else{

							next0 = vec[i].pos[1];
							next1 = vec[i].pos[0];
						}

						dist0 = min_dist[info.loc[0]][next0];
						dist1 = min_dist[info.loc[1]][next1];

						double next_dist = info.sum_dist+dist0+dist1;


						if(dp2[next0][next1] > next_dist+EPS){
							dp2[next0][next1] = next_dist;
							//★★PQには突っ込まない★★
						}else if(fabs(dp2[next0][next1]-next_dist) < EPS){

							//★初期位置から動かず★

						}else{

							continue; //★★注意★★
						}

						int to_0,to_1;

						for(int a = 0; a < G[next0].size(); a++){

							to_0 = G[next0][a].to;
							if(point[info.loc[0]].Y == point[to_0].Y)continue;
							if(point[to_0].Y > ans_Y[0])continue;
							for(int b = 0; b < G[next1].size(); b++){
								to_1 = G[next1][b].to;
								if(point[info.loc[1]].Y == point[to_1].Y)continue;
								if(to_1 == to_0)continue;
								if(point[to_1].Y > ans_Y[1])continue;

								double tmp_dist = next_dist+G[next0][a].dist+G[next1][b].dist;
								if(dp2[to_0][to_1] > tmp_dist+EPS){
									dp2[to_0][to_1] = tmp_dist;
									Q[NEXT].push(Info2(to_0,to_1,tmp_dist));
								}
							}
						}
					}
				}
			}
		}

		if(Q[NEXT].size() == 0){
			if(!STOP[0] && used[0]){
				STOP[0] = true;
				num_stop++;
			}
			if(!STOP[1] && used[1]){
				STOP[1] = true;
				num_stop++;
			}

			if(num_stop == 2){

				break;
			}else{

				if(STOP[0]){

					for(int i = 0; i < num_point; i++){

						if(fabs(dp2[T[0]][i]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info2(T[0],i,dp2[T[0]][i]));
					}

				}else{

					for(int i = 0; i < num_point; i++){

						if(fabs(dp2[i][T[1]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info2(i,T[1],dp2[i][T[1]]));
					}
				}

				if(Q[NEXT].size() == 0){

					break;
				}
			}
		}

		swap(CURRENT,NEXT);
	}

	if(fabs(dp2[T[0]][T[1]]-BIG_NUM) < EPS){

		printf("-1\n");

	}else{

		printf("%.10lf\n",dp2[T[0]][T[1]]);
	}
}

void func3(){

	for(int a = 0; a < num_point; a++){
		for(int b = 0; b < num_point; b++){
			for(int c = 0; c < num_point; c++){

				dp3[a][b][c] = BIG_NUM;
			}
		}
	}

	dp3[S[0]][S[1]][S[2]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info3> Q[2];
	Q[CURRENT].push(Info3(S[0],S[1],S[2],0));

	int num_stop = 0;
	bool STOP[3] = {false,false,false};
	bool used[3];

	while(true){

		//printf("num_stop:%d\n",num_stop);

		for(int i = 0; i < 3; i++){

			used[i] = false;
		}

		while(!Q[CURRENT].empty()){

			Info3 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			int minimum = BIG_NUM;
			int num_minimum = 0;
			int max_index = -1;

			for(int i = 0; i < 3; i++){

				if(STOP[i])continue;

				if(minimum > point[info.loc[i]].Y){
					minimum = point[info.loc[i]].Y;
					num_minimum = 1;
				}else if(minimum == point[info.loc[i]].Y){

					num_minimum++;
				}else{

					max_index = i;
				}
			}

			bool sameFLG = false;
			if(num_stop == 1){

				if(STOP[0]){

					if(get_boss(info.loc[1]) == get_boss(info.loc[2])){

						sameFLG = true;
					}

				}else if(STOP[1]){

					if(get_boss(info.loc[0]) == get_boss(info.loc[2])){

						sameFLG = true;
					}

				}else{

					if(get_boss(info.loc[1]) == get_boss(info.loc[2])){

						sameFLG = true;
					}
				}
			}

			if((num_minimum == 1) || (num_stop == 1 && !sameFLG) || (num_stop == 0 && get_boss(info.loc[0]) != get_boss(info.loc[1]) &&
					get_boss(info.loc[0]) != get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) != get_boss(info.loc[2]))){ //Yの最小値が1つ、または全てのグループが異なる

				int min_index;

				for(int i = 0; i < 3; i++){
					if(STOP[i])continue;

					if(point[info.loc[i]].Y == minimum){
						min_index = i;
						break;
					}
				}

				//動くのは一匹だけ

				int next[3];
				for(int k = 0; k < 3; k++){

					next[k] = info.loc[k];
				}

				used[min_index] = true;

				for(int i = 0; i < G[info.loc[min_index]].size(); i++){

					int next_node = G[info.loc[min_index]][i].to;
					if(next_node == info.loc[0] || next_node == info.loc[1] || next_node == info.loc[2])continue;
					if(point[next_node].Y > ans_Y[min_index])continue;

					double next_dist = info.sum_dist+G[info.loc[min_index]][i].dist;

					next[min_index] = next_node;

					if(dp3[next[0]][next[1]][next[2]] > next_dist+EPS){

						dp3[next[0]][next[1]][next[2]] = next_dist;
						Q[NEXT].push(Info3(next[0],next[1],next[2],next_dist));
					}
				}

			}else if(num_stop == 0 && get_boss(info.loc[0]) == get_boss(info.loc[1]) && get_boss(info.loc[0]) == get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) == get_boss(info.loc[2])){ //全てのグループが同じ

				//printf("全てのグループが同じ\n");
				//printf("L:%d R:%d\n",L[get_boss(info.loc[0])],R[get_boss(info.loc[0])]);
				//return;

				used[0] = true;
				used[1] = true;
				used[2] = true;

				vector<Data> data;
				for(int i = 0; i < 3; i++){

					data.push_back(Data(info.loc[i],i));
					work_L[i] = -1;
					work_R[i] = BIG_NUM;
				}

				sort(data.begin(),data.end());

				for(int i = 0; i < 3; i++){

					if(point[info.loc[data[i].loc_id]].Y == ans_Y[data[i].loc_id]){

						work_L[i] = T[data[i].loc_id];
						work_R[i] = T[data[i].loc_id];
					}
				}

				/*for(int i = 0; i < 3; i++){

					printf("p_id[%d]:%d\n",i,data[i].p_id);
				}*/

				//printf("L:%d R:%d\n",L[get_boss(data[0].p_id)],R[get_boss(data[0].p_id)]);

				vector<THREE> vec = calc_pos3(data[0].p_id,data[1].p_id,data[2].p_id);

				//printf("vec.size():%lld\n",vec.size());

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < vec.size(); i++){

					//printf("\ni:%d\n",i);

					for(int k = 0; k < 3; k++){

						TMP[data[k].loc_id] = vec[i].pos[k];
						tmp_d[data[k].loc_id] = min_dist[info.loc[data[k].loc_id]][TMP[data[k].loc_id]];
					}

					/*for(int k = 0; k < 3; k++){

						printf("TMP[%d]:%d\n",k,TMP[k]);
						printf("dist:%.3lf\n",tmp_d[k]);
					}*/

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

						//printf("最小値更新\n");

					}else if(fabs(dp3[TMP[0]][TMP[1]][TMP[2]]-next_dist) < EPS){

						//★初期位置から動かず★
						//printf("動かず\n");

					}else{

						//printf("不適\n");
						continue; //★★
					}

					int to_0,to_1,to_2;

					ll debug = 0;

					for(int a = 0; a < G[TMP[0]].size(); a++){
						to_0 = G[TMP[0]][a].to;
						if(point[to_0].Y == point[info.loc[0]].Y)continue;
						if(point[to_0].Y > ans_Y[0])continue;
						for(int b = 0; b < G[TMP[1]].size(); b++){
							to_1 = G[TMP[1]][b].to;
							if(point[to_1].Y == point[info.loc[1]].Y)continue;
							if(point[to_1].Y > ans_Y[1])continue;
							if(to_1 == to_0)continue;
							for(int c = 0; c < G[TMP[2]].size(); c++){
								to_2 = G[TMP[2]][c].to;
								if(point[to_2].Y == point[info.loc[2]].Y)continue;
								if(point[to_2].Y > ans_Y[2])continue;
								if(to_2 == to_0 || to_2 == to_1)continue;

								double tmp_dist = next_dist+G[TMP[0]][a].dist+G[TMP[1]][b].dist+G[TMP[2]][c].dist;

								if(dp3[to_0][to_1][to_2] > tmp_dist+EPS){
									debug++;
									dp3[to_0][to_1][to_2] = tmp_dist;
									Q[NEXT].push(Info3(to_0,to_1,to_2,tmp_dist));
								}
							}
						}
					}
				}

				/*printf("Q[CURRENT].size():%lld Q[NEXT].size():%lld\n",Q[CURRENT].size(),Q[NEXT].size());
				return;*/

			}else{ //グループが1匹+2匹で、2匹が下方,または1匹がストップ

				vector<Data> tmp_v;
				for(int i = 0; i < 3; i++){
					if(STOP[i])continue;
					if(point[info.loc[i]].Y == minimum){

						tmp_v.push_back(Data(info.loc[i],i));
						used[i] = true;
					}
				}

				sort(tmp_v.begin(),tmp_v.end());

				vector<TWO> vec = calc_pos2(tmp_v[0].p_id,tmp_v[1].p_id);

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < 3; i++){
					TMP[i] = info.loc[i];
					tmp_d[i] = 0;
				}

				for(int i = 0; i < vec.size(); i++){

					for(int k = 0; k < 2; k++){

						TMP[tmp_v[k].loc_id] = vec[i].pos[k];
						tmp_d[tmp_v[k].loc_id] = min_dist[info.loc[tmp_v[k].loc_id]][TMP[tmp_v[k].loc_id]];
					}

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

					}else if(fabs(dp3[TMP[0]][TMP[1]][TMP[2]]-next_dist) < EPS){

						//★初期位置から動かず★

					}else{

						continue; //★★
					}

					int to[3];
					for(int a = 0; a < 3; a++){

						to[a] = TMP[a];
					}

					for(int a = 0; a < G[tmp_v[0].loc_id].size(); a++){
						to[tmp_v[0].loc_id] = G[tmp_v[0].loc_id][a].to;
						if(point[to[tmp_v[0].loc_id]].Y == minimum)continue;
						if(point[to[tmp_v[0].loc_id]].Y > ans_Y[tmp_v[0].loc_id])continue;
						if(to[tmp_v[0].loc_id] == max_index)continue;

						for(int b = 0; b < G[tmp_v[1].loc_id].size(); b++){
							to[tmp_v[1].loc_id] = G[tmp_v[1].loc_id][b].to;
							if(point[to[tmp_v[1].loc_id]].Y == minimum)continue;
							if(point[to[tmp_v[1].loc_id]].Y > ans_Y[tmp_v[1].loc_id])continue;
							if(to[tmp_v[1].loc_id] == max_index || to[tmp_v[1].loc_id] == to[tmp_v[0].loc_id])continue;

							double tmp_dist = next_dist+G[tmp_v[0].loc_id][a].dist+G[tmp_v[1].loc_id][b].dist;

							if(dp3[to[0]][to[1]][to[2]] > tmp_dist+EPS){

								dp3[to[0]][to[1]][to[2]] = tmp_dist;
								Q[NEXT].push(Info3(to[0],to[1],to[2],tmp_dist));
							}
						}
					}
				}
			}
		}

		/*printf("Q[NEXT].size():%lld num_stop:%d\n",Q[NEXT].size(),num_stop);
							break;*/

		if(Q[NEXT].size() == 0){
			if(!STOP[0] && used[0]){
				STOP[0] = true;
				num_stop++;
			}
			if(!STOP[1] && used[1]){
				STOP[1] = true;
				num_stop++;
			}
			if(!STOP[2] && used[2]){
				STOP[2] = true;
				num_stop++;
			}
			if(num_stop == 3){

				break;
			}

			if(num_stop == 1){

				for(int i = 0; i < num_point; i++){
					for(int k = 0; k < num_point; k++){

						if(STOP[0]){

							if(fabs(dp3[T[0]][i][k]-BIG_NUM) < EPS){

								continue;
							}
							Q[NEXT].push(Info3(T[0],i,k,dp3[T[0]][i][k]));

						}else if(STOP[1]){

							if(fabs(dp3[i][T[1]][k]-BIG_NUM) < EPS){

								continue;
							}
							Q[NEXT].push(Info3(i,T[1],k,dp3[i][T[1]][k]));


						}else{ //STOP[2]

							if(fabs(dp3[i][k][T[2]]-BIG_NUM) < EPS)continue;

							Q[NEXT].push(Info3(i,k,T[2],dp3[i][k][T[2]]));
						}
					}
				}

			}else{ //num_stop == 2

				for(int i = 0; i < num_point; i++){

					if(!STOP[0]){

						if(fabs(dp3[i][T[1]][T[2]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(i,T[1],T[2],dp3[i][T[1]][T[2]]));

					}else if(!STOP[1]){

						if(fabs(dp3[T[0]][i][T[2]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(T[0],i,T[2],dp3[T[0]][i][T[2]]));

					}else{ //!STOP[2]

						if(fabs(dp3[T[0]][T[1]][i]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(T[0],T[1],i,dp3[T[0]][T[1]][i]));
					}
				}
			}

			if(Q[NEXT].size() == 0){

				break;
			}
		}

		swap(CURRENT,NEXT);
	}

	if(fabs(dp3[T[0]][T[1]][T[2]]-BIG_NUM) < EPS){

		printf("-1\n");
	}else{

		printf("%.10lf\n",dp3[T[0]][T[1]][T[2]]);
	}
}

int main(){

	scanf("%d %d",&N,&num_dog);
	scanf("%lf",&D);

	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_S[i]);
		first_S[i]--;
	}
	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_T[i]);
		first_T[i]--;
	}

	min_Y = BIG_NUM,max_Y = -BIG_NUM;

	for(int i = 0; i < N; i++){

		scanf("%d %d",&input[i].X,&input[i].Y);
		input[i].x = input[i].X;
		input[i].y = input[i].Y;

		min_Y = min(min_Y,input[i].Y);
		max_Y = max(max_Y,input[i].Y);

		P[input[i].Y].push_back(input[i]);
	}

	num_point = 0;

	for(int i = min_Y; i <= max_Y; i++){
		if(P[i].size() == 0)continue;

		sort(P[i].begin(),P[i].end());

		L[i] = num_point;
		point[num_point++] = P[i][0];

		for(int k = 1; k < P[i].size(); k++){

			R[i] = num_point;
			point[num_point++] = P[i][k];
		}
	}

	for(int i = 0; i < num_dog; i++){
		for(int k = 0; k < num_point; k++){
			if(input[first_S[i]] == point[k]){

				S[i] = k;
			}
			if(input[first_T[i]] == point[k]){

				T[i] = k;
			}
		}
	}

	for(int i = 0; i < num_point; i++){

		boss[i] = i;
		height[i] = i;
		L[i] = i;
		R[i] = i;
	}

	for(int i = 0; i < num_dog; i++){

		ans_Y[i] = point[T[i]].Y;
	}

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){

			if(k == i){

				min_dist[i][k] = 0;
			}else{

				min_dist[i][k] = BIG_NUM;
			}
		}
	}

	//エッジ張り
	for(int i = 0; i < num_point-1; i++){
		for(int k = i+1; k < num_point; k++){
			if(calc_dist(point[i],point[k]) > D+EPS)continue;

			bool FLG = true;
			Line tmp_line = Line(point[i],point[k]);
			for(int a = 0; a < num_point; a++){
				if(a == i || a == k)continue;

				if(getDistanceSP(tmp_line,point[a]) < EPS){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			if(point[i].Y == point[k].Y){

				unite(i,k);
				double tmp_dist = calc_dist(point[i],point[k]);
				G[i].push_back(Edge(k,tmp_dist));
				G[k].push_back(Edge(i,tmp_dist));

				min_dist[i][k] = tmp_dist;
				min_dist[k][i] = tmp_dist;
				//printf("%d-%dにエッジを張った\n",i,k);

			}else{

				int from = i;
				int to = k;
				if(point[i].Y > point[k].Y){

					swap(from,to);
				}
				G[from].push_back(Edge(to,calc_dist(point[i],point[k])));
				//printf("%d-%dにエッジを張った\n",from,to);
			}
		}
	}

	for(int mid = 0; mid < num_point; mid++){
		for(int start = 0; start < num_point; start++){
			if(fabs(min_dist[start][mid]-BIG_NUM) < EPS)continue;
			for(int goal = 0; goal < num_point; goal++){
				if(fabs(min_dist[mid][goal]-BIG_NUM) < EPS)continue;

				min_dist[start][goal] = min(min_dist[start][goal],min_dist[start][mid]+min_dist[mid][goal]);
			}
		}
	}

	if(num_dog == 1){

		func1();

	}else if(num_dog == 2){

		func2();

	}else{

		func3();
	}

	return 0;
}
accuracy: 0.6428571428571429
time_ms: 580
memory_kb: 36752
final_rank: 7

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 105
#define SIZE2 10005

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
		X = 0;
		Y = 0;
	}

	Point(){
		x = y = 0.0;
		X = Y = 0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{
		return x != p.x? x < p.x: y < p.y;
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}

   	/*
	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/

	double x,y;
	int X,Y;
};

typedef Point Vector;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};



struct Edge{
	Edge(int arg_to,double arg_dist){
		to = arg_to;
		dist = arg_dist;
	}
	int to;
	double dist;
};

struct State{
	State(int arg_node_id,double arg_sum_dist){
		node_id = arg_node_id;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct State &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int node_id;
	double sum_dist;
};

struct Info2{
	Info2(){

		loc[0] = loc[1] = 0;
		sum_dist = 0;
	}
	Info2(int arg_loc0,int arg_loc1,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info2 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}

	int loc[2];
	double sum_dist;
};

struct Info3{
	Info3(){

		loc[0] = loc[1] = loc[2] = 0;
		sum_dist = 0;
	}
	Info3(int arg_loc0,int arg_loc1,int arg_loc2,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		loc[2] = arg_loc2;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info3 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int loc[3];
	double sum_dist;
};

struct TWO{
	TWO(int arg_left,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_right;
	}
	int pos[2];
};

struct THREE{
	THREE(int arg_left,int arg_mid,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_mid;
		pos[2] = arg_right;
	}
	int pos[3];
};

struct Data{
	Data(int arg_p_id,int arg_loc_id){
		p_id = arg_p_id;
		loc_id = arg_loc_id;
	}
	bool operator<(const struct Data &arg) const{

		return p_id < arg.p_id;
	}

	int p_id,loc_id;
};


int N,num_dog;
int first_S[3],first_T[3];
int S[3],T[3];
int boss[SIZE],height[SIZE];
int L[SIZE],R[SIZE];
int work_L[3],work_R[3];
int num_point;
int min_Y,max_Y;
int ans_Y[3];
double D;
double dp[SIZE],dp2[SIZE][SIZE],dp3[SIZE][SIZE][SIZE];
double min_dist[SIZE][SIZE];
Point input[SIZE],point[SIZE];
vector<Point> P[SIZE2];
vector<Edge> G[SIZE];



int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		L[boss_y] = min(L[boss_y],L[boss_x]);
		R[boss_y] = max(R[boss_y],R[boss_x]);
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);

		boss[boss_y] = boss_x;
		height[x]++;
	}
}


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

void func1(){

	for(int i = 0; i < num_point; i++){

		dp[i] = BIG_NUM;
	}

	dp[S[0]] = 0;
	priority_queue<State> Q;

	Q.push(State(S[0],0));

	int next_node;
	double next_dist;

	while(!Q.empty()){

		if(Q.top().sum_dist > dp[Q.top().node_id]+EPS){

			Q.pop();
		}else if(Q.top().node_id == T[0]){

			printf("%.10lf\n",Q.top().sum_dist);
			return;

		}else{

			for(int i = 0; i < G[Q.top().node_id].size(); i++){

				next_node = G[Q.top().node_id][i].to;
				next_dist = Q.top().sum_dist+G[Q.top().node_id][i].dist;

				if(dp[next_node] > next_dist+EPS){
					dp[next_node] = next_dist;
					Q.push(State(next_node,next_dist));
				}
			}
			Q.pop();
		}
	}

	printf("-1\n");
}

vector<TWO> calc_pos2(int first_left,int first_right){

	vector<TWO> ret;
	int group_id = get_boss(first_left);

	for(int l = L[group_id]; l < first_right; l++){
		for(int r = max(l,first_left)+1; r <= R[group_id]; r++){

			ret.push_back(TWO(l,r));
		}
	}

	return ret;
}

vector<THREE> calc_pos3(int first_left,int first_mid,int first_right){

	vector<THREE> ret;
	int group_id = get_boss(first_left);

	for(int l = max(L[group_id],work_L[0]); l <= min(work_R[0],first_mid-1); l++){
		for(int m = max(max(l,first_left)+1,work_L[1]); m <= min(work_R[1],first_right-1); m++){
			for(int r = max(max(m,first_mid)+1,work_L[2]); r <= min(work_R[2],R[group_id]); r++){

				ret.push_back(THREE(l,m,r));
			}
		}
	}

	return ret;
}

void func2(){

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){
			dp2[i][k] = BIG_NUM;
		}
	}

	dp2[S[0]][S[1]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info2> Q[2];
	Q[CURRENT].push(Info2(S[0],S[1],0));

	bool STOP[2] = {false,false};
	bool used[2];

	int num_stop = 0;

	while(true){

		used[0] = false;
		used[1] = false;

		while(!Q[CURRENT].empty()){

			Info2 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			if(info.sum_dist > dp2[info.loc[0]][info.loc[1]]+EPS){

				continue;

			}else{

				if(get_boss(info.loc[0]) != get_boss(info.loc[1]) || num_stop == 1){

					if((STOP[1]) || (!STOP[0] && point[info.loc[0]].Y <= point[info.loc[1]].Y)){

						used[0] = true;

						for(int i = 0; i < G[info.loc[0]].size(); i++){

							int next_node = G[info.loc[0]][i].to;
							if(point[next_node].Y > ans_Y[0] || next_node == info.loc[1])continue;
							double next_dist = info.sum_dist+G[info.loc[0]][i].dist;

							if(dp2[next_node][info.loc[1]] > next_dist+EPS){
								dp2[next_node][info.loc[1]] = next_dist;
								Q[NEXT].push(Info2(next_node,info.loc[1],next_dist));
							}
						}

					}else{

						used[1] = true;

						for(int i = 0; i < G[info.loc[1]].size(); i++){

							int next_node = G[info.loc[1]][i].to;
							if(point[next_node].Y > ans_Y[1] || next_node == info.loc[0])continue;
							double next_dist = info.sum_dist+G[info.loc[1]][i].dist;

							if(dp2[info.loc[0]][next_node] > next_dist+EPS){
								dp2[info.loc[0]][next_node] = next_dist;
								Q[NEXT].push(Info2(info.loc[0],next_node,next_dist));
							}
						}
					}

				}else{ //同グループ

					used[0] = true;
					used[1] = true;

					vector<TWO> vec = calc_pos2(min(info.loc[0],info.loc[1]),max(info.loc[0],info.loc[1]));

					int next0,next1,dist0,dist1;

					for(int i = 0; i < vec.size(); i++){

						if(info.loc[0] < info.loc[1]){ //index順とXの大小は一致している

							next0 = vec[i].pos[0];
							next1 = vec[i].pos[1];

						}else{

							next0 = vec[i].pos[1];
							next1 = vec[i].pos[0];
						}

						dist0 = min_dist[info.loc[0]][next0];
						dist1 = min_dist[info.loc[1]][next1];

						double next_dist = info.sum_dist+dist0+dist1;


						if(dp2[next0][next1] > next_dist+EPS){
							dp2[next0][next1] = next_dist;
							//★★PQには突っ込まない★★
						}else if(fabs(dp2[next0][next1]-next_dist) < EPS){

							//★初期位置から動かず★

						}else{

							continue; //★★注意★★
						}

						int to_0,to_1;

						for(int a = 0; a < G[next0].size(); a++){

							to_0 = G[next0][a].to;
							if(point[info.loc[0]].Y == point[to_0].Y)continue;
							if(point[to_0].Y > ans_Y[0])continue;
							for(int b = 0; b < G[next1].size(); b++){
								to_1 = G[next1][b].to;
								if(point[info.loc[1]].Y == point[to_1].Y)continue;
								if(to_1 == to_0)continue;
								if(point[to_1].Y > ans_Y[1])continue;

								double tmp_dist = next_dist+G[next0][a].dist+G[next1][b].dist;
								if(dp2[to_0][to_1] > tmp_dist+EPS){
									dp2[to_0][to_1] = tmp_dist;
									Q[NEXT].push(Info2(to_0,to_1,tmp_dist));
								}
							}
						}
					}
				}
			}
		}

		if(Q[NEXT].size() == 0){
			if(!STOP[0] && used[0]){
				STOP[0] = true;
				num_stop++;
			}
			if(!STOP[1] && used[1]){
				STOP[1] = true;
				num_stop++;
			}

			if(num_stop == 2){

				break;
			}else{

				if(STOP[0]){

					for(int i = 0; i < num_point; i++){

						if(fabs(dp2[T[0]][i]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info2(T[0],i,dp2[T[0]][i]));
					}

				}else{

					for(int i = 0; i < num_point; i++){

						if(fabs(dp2[i][T[1]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info2(i,T[1],dp2[i][T[1]]));
					}
				}

				if(Q[NEXT].size() == 0){

					break;
				}
			}
		}

		swap(CURRENT,NEXT);
	}

	if(fabs(dp2[T[0]][T[1]]-BIG_NUM) < EPS){

		printf("-1\n");

	}else{

		printf("%.10lf\n",dp2[T[0]][T[1]]);
	}
}

void func3(){

	for(int a = 0; a < num_point; a++){
		for(int b = 0; b < num_point; b++){
			for(int c = 0; c < num_point; c++){

				dp3[a][b][c] = BIG_NUM;
			}
		}
	}

	dp3[S[0]][S[1]][S[2]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info3> Q[2];
	Q[CURRENT].push(Info3(S[0],S[1],S[2],0));

	int num_stop = 0;
	bool STOP[3] = {false,false,false};
	bool used[3];

	while(true){

		//printf("num_stop:%d\n",num_stop);

		for(int i = 0; i < 3; i++){

			used[i] = false;
		}

		while(!Q[CURRENT].empty()){

			Info3 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			int minimum = BIG_NUM;
			int num_minimum = 0;
			int max_index = -1;

			for(int i = 0; i < 3; i++){

				if(STOP[i])continue;

				if(minimum > point[info.loc[i]].Y){
					minimum = point[info.loc[i]].Y;
					num_minimum = 1;
				}else if(minimum == point[info.loc[i]].Y){

					num_minimum++;
				}else{

					max_index = i;
				}
			}

			bool sameFLG = false;
			if(num_stop == 1){

				if(STOP[0]){

					if(get_boss(info.loc[1]) == get_boss(info.loc[2])){

						sameFLG = true;
					}

				}else if(STOP[1]){

					if(get_boss(info.loc[0]) == get_boss(info.loc[2])){

						sameFLG = true;
					}

				}else{

					if(get_boss(info.loc[1]) == get_boss(info.loc[2])){

						sameFLG = true;
					}
				}
			}

			if((num_minimum == 1) || (num_stop == 1 && !sameFLG) || (num_stop == 0 && get_boss(info.loc[0]) != get_boss(info.loc[1]) &&
					get_boss(info.loc[0]) != get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) != get_boss(info.loc[2]))){ //Yの最小値が1つ、または全てのグループが異なる

				int min_index;

				for(int i = 0; i < 3; i++){
					if(STOP[i])continue;

					if(point[info.loc[i]].Y == minimum){
						min_index = i;
						break;
					}
				}

				//動くのは一匹だけ

				int next[3];
				for(int k = 0; k < 3; k++){

					next[k] = info.loc[k];
				}

				used[min_index] = true;

				for(int i = 0; i < G[info.loc[min_index]].size(); i++){

					int next_node = G[info.loc[min_index]][i].to;
					if(next_node == info.loc[0] || next_node == info.loc[1] || next_node == info.loc[2])continue;
					if(point[next_node].Y > ans_Y[min_index])continue;

					double next_dist = info.sum_dist+G[info.loc[min_index]][i].dist;

					next[min_index] = next_node;

					if(dp3[next[0]][next[1]][next[2]] > next_dist+EPS){

						dp3[next[0]][next[1]][next[2]] = next_dist;
						Q[NEXT].push(Info3(next[0],next[1],next[2],next_dist));
					}
				}

			}else if(num_stop == 0 && get_boss(info.loc[0]) == get_boss(info.loc[1]) && get_boss(info.loc[0]) == get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) == get_boss(info.loc[2])){ //全てのグループが同じ

				//printf("全てのグループが同じ\n");
				//printf("L:%d R:%d\n",L[get_boss(info.loc[0])],R[get_boss(info.loc[0])]);
				//return;

				used[0] = true;
				used[1] = true;
				used[2] = true;

				vector<Data> data;
				for(int i = 0; i < 3; i++){

					data.push_back(Data(info.loc[i],i));
					work_L[i] = -1;
					work_R[i] = BIG_NUM;
				}

				sort(data.begin(),data.end());

				for(int i = 0; i < 3; i++){

					if(point[info.loc[data[i].loc_id]].Y == ans_Y[data[i].loc_id]){

						work_L[i] = T[data[i].loc_id];
						work_R[i] = T[data[i].loc_id];
					}
				}

				/*for(int i = 0; i < 3; i++){

					printf("p_id[%d]:%d\n",i,data[i].p_id);
				}*/

				//printf("L:%d R:%d\n",L[get_boss(data[0].p_id)],R[get_boss(data[0].p_id)]);

				vector<THREE> vec = calc_pos3(data[0].p_id,data[1].p_id,data[2].p_id);

				//printf("vec.size():%lld\n",vec.size());

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < vec.size(); i++){

					//printf("\ni:%d\n",i);

					for(int k = 0; k < 3; k++){

						TMP[data[k].loc_id] = vec[i].pos[k];
						tmp_d[data[k].loc_id] = min_dist[info.loc[data[k].loc_id]][TMP[data[k].loc_id]];
					}

					/*for(int k = 0; k < 3; k++){

						printf("TMP[%d]:%d\n",k,TMP[k]);
						printf("dist:%.3lf\n",tmp_d[k]);
					}*/

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

						//printf("最小値更新\n");

					}else if(fabs(dp3[TMP[0]][TMP[1]][TMP[2]]-next_dist) < EPS){

						//★初期位置から動かず★
						//printf("動かず\n");

					}else{

						//printf("不適\n");
						continue; //★★
					}

					int to_0,to_1,to_2;

					ll debug = 0;

					for(int a = 0; a < G[TMP[0]].size(); a++){
						to_0 = G[TMP[0]][a].to;
						if(point[to_0].Y == point[info.loc[0]].Y)continue;
						if(point[to_0].Y > ans_Y[0])continue;
						for(int b = 0; b < G[TMP[1]].size(); b++){
							to_1 = G[TMP[1]][b].to;
							if(point[to_1].Y == point[info.loc[1]].Y)continue;
							if(point[to_1].Y > ans_Y[1])continue;
							if(to_1 == to_0)continue;
							for(int c = 0; c < G[TMP[2]].size(); c++){
								to_2 = G[TMP[2]][c].to;
								if(point[to_2].Y == point[info.loc[2]].Y)continue;
								if(point[to_2].Y > ans_Y[2])continue;
								if(to_2 == to_0 || to_2 == to_1)continue;

								double tmp_dist = next_dist+G[TMP[0]][a].dist+G[TMP[1]][b].dist+G[TMP[2]][c].dist;

								if(dp3[to_0][to_1][to_2] > tmp_dist+EPS){
									debug++;
									dp3[to_0][to_1][to_2] = tmp_dist;
									Q[NEXT].push(Info3(to_0,to_1,to_2,tmp_dist));
								}
							}
						}
					}
				}

				/*printf("Q[CURRENT].size():%lld Q[NEXT].size():%lld\n",Q[CURRENT].size(),Q[NEXT].size());
				return;*/

			}else{ //グループが1匹+2匹で、2匹が下方,または1匹がストップ

				vector<Data> tmp_v;
				for(int i = 0; i < 3; i++){
					if(STOP[i])continue;
					if(point[info.loc[i]].Y == minimum){

						tmp_v.push_back(Data(info.loc[i],i));
						used[i] = true;
					}
				}

				sort(tmp_v.begin(),tmp_v.end());

				vector<TWO> vec = calc_pos2(tmp_v[0].p_id,tmp_v[1].p_id);

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < 3; i++){
					TMP[i] = info.loc[i];
					tmp_d[i] = 0;
				}

				for(int i = 0; i < vec.size(); i++){

					for(int k = 0; k < 2; k++){

						TMP[tmp_v[k].loc_id] = vec[i].pos[k];
						tmp_d[tmp_v[k].loc_id] = min_dist[info.loc[tmp_v[k].loc_id]][TMP[tmp_v[k].loc_id]];
					}

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

					}else if(fabs(dp3[TMP[0]][TMP[1]][TMP[2]]-next_dist) < EPS){

						//★初期位置から動かず★

					}else{

						continue; //★★
					}

					int to[3];
					for(int a = 0; a < 3; a++){

						to[a] = TMP[a];
					}

					for(int a = 0; a < G[tmp_v[0].loc_id].size(); a++){
						to[tmp_v[0].loc_id] = G[tmp_v[0].loc_id][a].to;
						if(point[to[tmp_v[0].loc_id]].Y == minimum)continue;
						if(point[to[tmp_v[0].loc_id]].Y > ans_Y[tmp_v[0].loc_id])continue;
						if(to[tmp_v[0].loc_id] == max_index)continue;

						for(int b = 0; b < G[tmp_v[1].loc_id].size(); b++){
							to[tmp_v[1].loc_id] = G[tmp_v[1].loc_id][b].to;
							if(point[to[tmp_v[1].loc_id]].Y == minimum)continue;
							if(point[to[tmp_v[1].loc_id]].Y > ans_Y[tmp_v[1].loc_id])continue;
							if(to[tmp_v[1].loc_id] == max_index || to[tmp_v[1].loc_id] == to[tmp_v[0].loc_id])continue;

							double tmp_dist = next_dist+G[tmp_v[0].loc_id][a].dist+G[tmp_v[1].loc_id][b].dist;

							if(dp3[to[0]][to[1]][to[2]] > tmp_dist+EPS){

								dp3[to[0]][to[1]][to[2]] = tmp_dist;
								Q[NEXT].push(Info3(to[0],to[1],to[2],tmp_dist));
							}
						}
					}
				}
			}
		}

		/*printf("Q[NEXT].size():%lld num_stop:%d\n",Q[NEXT].size(),num_stop);
							break;*/

		if(Q[NEXT].size() == 0){
			if(!STOP[0] && used[0]){
				STOP[0] = true;
				num_stop++;
			}
			if(!STOP[1] && used[1]){
				STOP[1] = true;
				num_stop++;
			}
			if(!STOP[2] && used[2]){
				STOP[2] = true;
				num_stop++;
			}
			if(num_stop == 3){

				break;
			}

			if(num_stop == 1){

				for(int i = 0; i < num_point; i++){
					for(int k = 0; k < num_point; k++){

						if(STOP[0]){

							if(fabs(dp3[T[0]][i][k]-BIG_NUM) < EPS){

								continue;
							}
							Q[NEXT].push(Info3(T[0],i,k,dp3[T[0]][i][k]));

						}else if(STOP[1]){

							if(fabs(dp3[i][T[1]][k]-BIG_NUM) < EPS){

								continue;
							}
							Q[NEXT].push(Info3(i,T[1],k,dp3[i][T[1]][k]));


						}else{ //STOP[2]

							if(fabs(dp3[i][k][T[2]]-BIG_NUM) < EPS)continue;

							Q[NEXT].push(Info3(i,k,T[2],dp3[i][k][T[2]]));
						}
					}
				}

			}else{ //num_stop == 2

				for(int i = 0; i < num_point; i++){

					if(!STOP[0]){

						if(fabs(dp3[i][T[1]][T[2]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(i,T[1],T[2],dp3[i][T[1]][T[2]]));

					}else if(!STOP[1]){

						if(fabs(dp3[T[0]][i][T[2]]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(T[0],i,T[2],dp3[T[0]][i][T[2]]));

					}else{ //!STOP[2]

						if(fabs(dp3[T[0]][T[1]][i]-BIG_NUM) < EPS)continue;

						Q[NEXT].push(Info3(T[0],T[1],i,dp3[T[0]][T[1]][i]));
					}
				}
			}

			printf("Q[NEXT].size():%lld num_stop:%d\n",Q[NEXT].size(),num_stop);
					break;

			if(Q[NEXT].size() == 0){

				break;
			}
		}

		swap(CURRENT,NEXT);
	}

	if(fabs(dp3[T[0]][T[1]][T[2]]-BIG_NUM) < EPS){

		printf("-1\n");
	}else{

		printf("%.10lf\n",dp3[T[0]][T[1]][T[2]]);
	}
}

int main(){

	scanf("%d %d",&N,&num_dog);
	scanf("%lf",&D);

	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_S[i]);
		first_S[i]--;
	}
	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_T[i]);
		first_T[i]--;
	}

	min_Y = BIG_NUM,max_Y = -BIG_NUM;

	for(int i = 0; i < N; i++){

		scanf("%d %d",&input[i].X,&input[i].Y);
		input[i].x = input[i].X;
		input[i].y = input[i].Y;

		min_Y = min(min_Y,input[i].Y);
		max_Y = max(max_Y,input[i].Y);

		P[input[i].Y].push_back(input[i]);
	}

	num_point = 0;

	for(int i = min_Y; i <= max_Y; i++){
		if(P[i].size() == 0)continue;

		sort(P[i].begin(),P[i].end());

		L[i] = num_point;
		point[num_point++] = P[i][0];

		for(int k = 1; k < P[i].size(); k++){

			R[i] = num_point;
			point[num_point++] = P[i][k];
		}
	}

	for(int i = 0; i < num_dog; i++){
		for(int k = 0; k < num_point; k++){
			if(input[first_S[i]] == point[k]){

				S[i] = k;
			}
			if(input[first_T[i]] == point[k]){

				T[i] = k;
			}
		}
	}

	for(int i = 0; i < num_point; i++){

		boss[i] = i;
		height[i] = i;
		L[i] = i;
		R[i] = i;
	}

	for(int i = 0; i < num_dog; i++){

		ans_Y[i] = point[T[i]].Y;
	}

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){

			if(k == i){

				min_dist[i][k] = 0;
			}else{

				min_dist[i][k] = BIG_NUM;
			}
		}
	}

	//エッジ張り
	for(int i = 0; i < num_point-1; i++){
		for(int k = i+1; k < num_point; k++){
			if(calc_dist(point[i],point[k]) > D+EPS)continue;

			bool FLG = true;
			Line tmp_line = Line(point[i],point[k]);
			for(int a = 0; a < num_point; a++){
				if(a == i || a == k)continue;

				if(getDistanceSP(tmp_line,point[a]) < EPS){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			if(point[i].Y == point[k].Y){

				unite(i,k);
				double tmp_dist = calc_dist(point[i],point[k]);
				G[i].push_back(Edge(k,tmp_dist));
				G[k].push_back(Edge(i,tmp_dist));

				min_dist[i][k] = tmp_dist;
				min_dist[k][i] = tmp_dist;
				//printf("%d-%dにエッジを張った\n",i,k);

			}else{

				int from = i;
				int to = k;
				if(point[i].Y > point[k].Y){

					swap(from,to);
				}
				G[from].push_back(Edge(to,calc_dist(point[i],point[k])));
				//printf("%d-%dにエッジを張った\n",from,to);
			}
		}
	}

	for(int mid = 0; mid < num_point; mid++){
		for(int start = 0; start < num_point; start++){
			if(fabs(min_dist[start][mid]-BIG_NUM) < EPS)continue;
			for(int goal = 0; goal < num_point; goal++){
				if(fabs(min_dist[mid][goal]-BIG_NUM) < EPS)continue;

				min_dist[start][goal] = min(min_dist[start][goal],min_dist[start][mid]+min_dist[mid][goal]);
			}
		}
	}

	if(num_dog == 1){

		func1();

	}else if(num_dog == 2){

		func2();

	}else{

		func3();
	}

	return 0;
}
accuracy: 0.6428571428571429
time_ms: 590
memory_kb: 36812
final_rank: 9

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 105
#define SIZE2 10005

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
		X = 0;
		Y = 0;
	}

	Point(){
		x = y = 0.0;
		X = Y = 0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{
		return x != p.x? x < p.x: y < p.y;
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}

   	/*
	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/

	double x,y;
	int X,Y;
};

typedef Point Vector;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};



struct Edge{
	Edge(int arg_to,double arg_dist){
		to = arg_to;
		dist = arg_dist;
	}
	int to;
	double dist;
};

struct State{
	State(int arg_node_id,double arg_sum_dist){
		node_id = arg_node_id;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct State &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int node_id;
	double sum_dist;
};

struct Info2{
	Info2(){

		loc[0] = loc[1] = 0;
		sum_dist = 0;
	}
	Info2(int arg_loc0,int arg_loc1,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info2 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}

	int loc[2];
	double sum_dist;
};

struct Info3{
	Info3(){

		loc[0] = loc[1] = loc[2] = 0;
		sum_dist = 0;
	}
	Info3(int arg_loc0,int arg_loc1,int arg_loc2,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		loc[2] = arg_loc2;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info3 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int loc[3];
	double sum_dist;
};

struct TWO{
	TWO(int arg_left,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_right;
	}
	int pos[2];
};

struct THREE{
	THREE(int arg_left,int arg_mid,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_mid;
		pos[2] = arg_right;
	}
	int pos[3];
};

struct Data{
	Data(int arg_p_id,int arg_loc_id){
		p_id = arg_p_id;
		loc_id = arg_loc_id;
	}
	bool operator<(const struct Data &arg) const{

		return p_id < arg.p_id;
	}

	int p_id,loc_id;
};


int N,num_dog;
int first_S[3],first_T[3];
int S[3],T[3];
int boss[SIZE],height[SIZE];
int L[SIZE],R[SIZE];
int num_point;
int min_Y,max_Y;
double D;
double dp[SIZE],dp2[SIZE][SIZE],dp3[SIZE][SIZE][SIZE];
double min_dist[SIZE][SIZE];
Point input[SIZE],point[SIZE];
vector<Point> P[SIZE2];
vector<Edge> G[SIZE];



int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		L[boss_y] = min(L[boss_y],L[boss_x]);
		R[boss_y] = max(R[boss_y],R[boss_x]);
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);

		boss[boss_y] = boss_x;
		height[x]++;
	}
}


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

void func1(){

	for(int i = 0; i < num_point; i++){

		dp[i] = BIG_NUM;
	}

	dp[S[0]] = 0;
	priority_queue<State> Q;

	Q.push(State(S[0],0));

	int next_node;
	double next_dist;

	while(!Q.empty()){

		if(Q.top().sum_dist > dp[Q.top().node_id]+EPS){

			Q.pop();
		}else if(Q.top().node_id == T[0]){

			printf("%.10lf\n",Q.top().sum_dist);
			return;

		}else{

			for(int i = 0; i < G[Q.top().node_id].size(); i++){

				next_node = G[Q.top().node_id][i].to;
				next_dist = Q.top().sum_dist+G[Q.top().node_id][i].dist;

				if(dp[next_node] > next_dist+EPS){
					dp[next_node] = next_dist;
					Q.push(State(next_node,next_dist));
				}
			}
			Q.pop();
		}
	}

	printf("-1\n");
}

vector<TWO> calc_pos2(int first_left,int first_right){

	vector<TWO> ret;
	int group_id = get_boss(first_left);

	for(int l = L[group_id]; l < first_right; l++){
		for(int r = max(l,first_left)+1; r <= R[group_id]; r++){

			ret.push_back(TWO(l,r));
		}
	}

	return ret;
}

vector<THREE> calc_pos3(int first_left,int first_mid,int first_right){

	vector<THREE> ret;
	int group_id = get_boss(first_left);

	for(int l = L[group_id]; l < first_mid; l++){
		for(int m = max(l,first_left)+1; m < first_right; m++){
			for(int r = max(m,first_mid)+1; r <= R[group_id]; r++){

				ret.push_back(THREE(l,m,r));
			}
		}
	}

	return ret;
}

void func2(){

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){
			dp2[i][k] = BIG_NUM;
		}
	}

	dp2[S[0]][S[1]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info2> Q[2];
	Q[CURRENT].push(Info2(S[0],S[1],0));

	while(true){

		while(!Q[CURRENT].empty()){

			Info2 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			if(info.sum_dist > dp2[info.loc[0]][info.loc[1]]+EPS){

				continue;

			}else{

				if(get_boss(info.loc[0]) != get_boss(info.loc[1])){

					if(point[info.loc[0]].Y <= point[info.loc[1]].Y){

						for(int i = 0; i < G[info.loc[0]].size(); i++){

							int next_node = G[info.loc[0]][i].to;
							if(next_node == info.loc[1])continue;
							double next_dist = info.sum_dist+G[info.loc[0]][i].dist;

							if(dp2[next_node][info.loc[1]] > next_dist+EPS){
								dp2[next_node][info.loc[1]] = next_dist;
								Q[NEXT].push(Info2(next_node,info.loc[1],next_dist));
							}
						}

					}else{

						for(int i = 0; i < G[info.loc[1]].size(); i++){

							int next_node = G[info.loc[1]][i].to;
							if(next_node == info.loc[0])continue;
							double next_dist = info.sum_dist+G[info.loc[1]][i].dist;

							if(dp2[info.loc[0]][next_node] > next_dist+EPS){
								dp2[info.loc[0]][next_node] = next_dist;
								Q[NEXT].push(Info2(info.loc[0],next_node,next_dist));
							}
						}
					}

				}else{ //同グループ

					vector<TWO> vec = calc_pos2(min(info.loc[0],info.loc[1]),max(info.loc[0],info.loc[1]));

					int next0,next1,dist0,dist1;

					for(int i = 0; i < vec.size(); i++){

						if(info.loc[0] < info.loc[1]){ //index順とXの大小は一致している

							next0 = vec[i].pos[0];
							next1 = vec[i].pos[1];

						}else{

							next0 = vec[i].pos[1];
							next1 = vec[i].pos[0];
						}

						dist0 = min_dist[info.loc[0]][next0];
						dist1 = min_dist[info.loc[1]][next1];

						double next_dist = info.sum_dist+dist0+dist1;


						if(dp2[next0][next1] > next_dist+EPS){
							dp2[next0][next1] = next_dist;
							//★★PQには突っ込まない★★
						}else if(fabs(dp2[next0][next1]-next_dist) < EPS){

							//★初期位置から動かず★

						}else{

							continue; //★★注意★★
						}

						int to_0,to_1;

						for(int a = 0; a < G[next0].size(); a++){

							to_0 = G[next0][a].to;
							if(point[info.loc[0]].Y == point[to_0].Y)continue;
							for(int b = 0; b < G[next1].size(); b++){
								to_1 = G[next1][b].to;
								if(point[info.loc[1]].Y == point[to_1].Y)continue;
								if(to_1 == to_0)continue;

								double tmp_dist = next_dist+G[next0][a].dist+G[next1][b].dist;
								if(dp2[to_0][to_1] > tmp_dist+EPS){
									dp2[to_0][to_1] = tmp_dist;
									Q[NEXT].push(Info2(to_0,to_1,tmp_dist));
								}
							}
						}
					}
				}
			}
		}

		if(Q[NEXT].size() == 0)break;

		swap(CURRENT,NEXT);
	}

	if(fabs(dp2[T[0]][T[1]]-BIG_NUM) < EPS){

		printf("-1\n");

	}else{

		printf("%.10lf\n",dp2[T[0]][T[1]]);
	}
}

void func3(){

	for(int a = 0; a < num_point; a++){
		for(int b = 0; b < num_point; b++){
			for(int c = 0; c < num_point; c++){

				dp3[a][b][c] = BIG_NUM;
			}
		}
	}

	dp3[S[0]][S[1]][S[2]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info3> Q[2];
	Q[CURRENT].push(Info3(S[0],S[1],S[2],0));

	while(true){

		while(!Q[CURRENT].empty()){

			Info3 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			int minimum = BIG_NUM;
			int num_minimum = 0;
			int max_index;

			for(int i = 0; i < 3; i++){

				if(minimum > point[info.loc[i]].Y){
					minimum = point[info.loc[i]].Y;
					num_minimum = 1;
				}else if(minimum == point[info.loc[i]].Y){

					num_minimum++;
				}else{

					max_index = i;
				}
			}

			if((num_minimum == 1) || (get_boss(info.loc[0]) != get_boss(info.loc[1]) && get_boss(info.loc[0]) != get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) != get_boss(info.loc[2]))){ //Yの最小値が1つ、または全てのグループが異なる

				int min_index;

				for(int i = 0; i < 3; i++){

					if(point[info.loc[i]].Y == minimum){
						min_index = i;
						break;
					}
				}

				//動くのは一匹だけ

				int next[3];
				for(int k = 0; k < 3; k++){

					next[k] = info.loc[k];
				}

				for(int i = 0; i < G[info.loc[min_index]].size(); i++){

					int next_node = G[info.loc[min_index]][i].to;
					double next_dist = info.sum_dist+G[info.loc[min_index]][i].dist;

					next[min_index] = next_node;

					if(dp3[next[0]][next[1]][next[2]] > next_dist+EPS){

						dp3[next[0]][next[1]][next[2]] = next_dist;
						Q[NEXT].push(Info3(next[0],next[1],next[2],next_dist));
					}
				}

			}else if(get_boss(info.loc[0]) == get_boss(info.loc[1]) && get_boss(info.loc[0]) == get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) == get_boss(info.loc[2])){ //全てのグループが同じ

				//printf("全てのグループが同じ\n");


				vector<Data> data;
				for(int i = 0; i < 3; i++){

					data.push_back(Data(info.loc[i],i));
				}

				sort(data.begin(),data.end());
				/*for(int i = 0; i < 3; i++){

					printf("p_id[%d]:%d\n",i,data[i].p_id);
				}*/

				//printf("L:%d R:%d\n",L[get_boss(data[0].p_id)],R[get_boss(data[0].p_id)]);

				vector<THREE> vec = calc_pos3(data[0].p_id,data[1].p_id,data[2].p_id);

				//printf("vec.size():%lld\n",vec.size());

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < vec.size(); i++){

					//printf("\ni:%d\n",i);

					for(int k = 0; k < 3; k++){

						TMP[data[k].loc_id] = vec[i].pos[k];
						tmp_d[data[k].loc_id] = min_dist[info.loc[data[k].loc_id]][TMP[data[k].loc_id]];
					}

					/*for(int k = 0; k < 3; k++){

						printf("TMP[%d]:%d\n",k,TMP[k]);
						printf("dist:%.3lf\n",tmp_d[k]);
					}*/

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

						//printf("最小値更新\n");

					}else if(fabs(dp3[TMP[0]][TMP[1]][TMP[2]]-next_dist) < EPS){

						//★初期位置から動かず★
						//printf("動かず\n");

					}else{

						//printf("不適\n");
						continue; //★★
					}

					int to_0,to_1,to_2;

					for(int a = 0; a < G[TMP[0]].size(); a++){
						to_0 = G[TMP[0]][a].to;
						if(point[to_0].Y == point[info.loc[0]].Y)continue;
						for(int b = 0; b < G[TMP[1]].size(); b++){
							to_1 = G[TMP[1]][b].to;
							if(point[to_1].Y == point[info.loc[1]].Y)continue;
							if(to_1 == to_0)continue;
							for(int c = 0; c < G[TMP[2]].size(); c++){
								to_2 = G[TMP[2]][c].to;
								if(point[to_2].Y == point[info.loc[2]].Y)continue;
								if(to_2 == to_0 || to_2 == to_1)continue;

								double tmp_dist = next_dist+G[TMP[0]][a].dist+G[TMP[1]][b].dist+G[TMP[2]][c].dist;

								if(dp3[to_0][to_1][to_2] > tmp_dist+EPS){
									dp3[to_0][to_1][to_2] = tmp_dist;
									Q[NEXT].push(Info3(to_0,to_1,to_2,tmp_dist));
								}
							}
						}
					}
				}

			}else{ //グループが1匹+2匹で、2匹が下方

				vector<Data> tmp_v;
				for(int i = 0; i < 3; i++){
					if(point[info.loc[i]].Y == minimum){

						tmp_v.push_back(Data(info.loc[i],i));
					}
				}

				sort(tmp_v.begin(),tmp_v.end());

				vector<TWO> vec = calc_pos2(tmp_v[0].p_id,tmp_v[1].p_id);

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < 3; i++){
					TMP[i] = info.loc[i];
					tmp_d[i] = 0;
				}

				for(int i = 0; i < vec.size(); i++){

					for(int k = 0; k < 2; k++){

						TMP[tmp_v[k].loc_id] = vec[i].pos[k];
						tmp_d[tmp_v[k].loc_id] = min_dist[info.loc[tmp_v[k].loc_id]][TMP[tmp_v[k].loc_id]];
					}

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

					}else if(fabs(dp3[TMP[0]][TMP[1]][TMP[2]]-next_dist) < EPS){

						//★初期位置から動かず★

					}else{

						continue; //★★
					}

					int to[3];
					for(int a = 0; a < 3; a++){

						to[a] = TMP[a];
					}

					for(int a = 0; a < G[tmp_v[0].loc_id].size(); a++){
						to[tmp_v[0].loc_id] = G[tmp_v[0].loc_id][a].to;
						if(point[to[tmp_v[0].loc_id]].Y == minimum)continue;
						if(to[tmp_v[0].loc_id] == max_index)continue;
						for(int b = 0; b < G[tmp_v[1].loc_id].size(); b++){
							to[tmp_v[1].loc_id] = G[tmp_v[1].loc_id][b].to;
							if(point[to[tmp_v[1].loc_id]].Y == minimum)continue;
							if(to[tmp_v[1].loc_id] == max_index || to[tmp_v[1].loc_id] == to[tmp_v[0].loc_id])continue;

							double tmp_dist = next_dist+G[tmp_v[0].loc_id][a].dist+G[tmp_v[1].loc_id][b].dist;

							if(dp3[to[0]][to[1]][to[2]] > tmp_dist+EPS){

								dp3[to[0]][to[1]][to[2]] = tmp_dist;
								Q[NEXT].push(Info3(to[0],to[1],to[2],tmp_dist));
							}
						}
					}
				}
			}
		}

		if(Q[NEXT].size() == 0)break;

		swap(CURRENT,NEXT);
	}

	if(fabs(dp3[T[0]][T[1]][T[2]]-BIG_NUM) < EPS){

		printf("-1\n");
	}else{

		printf("%.10lf\n",dp3[T[0]][T[1]][T[2]]);
	}
}

int main(){

	scanf("%d %d",&N,&num_dog);
	scanf("%lf",&D);

	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_S[i]);
		first_S[i]--;
	}
	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_T[i]);
		first_T[i]--;
	}

	min_Y = BIG_NUM,max_Y = -BIG_NUM;

	for(int i = 0; i < N; i++){

		scanf("%d %d",&input[i].X,&input[i].Y);
		input[i].x = input[i].X;
		input[i].y = input[i].Y;

		min_Y = min(min_Y,input[i].Y);
		max_Y = max(max_Y,input[i].Y);

		P[input[i].Y].push_back(input[i]);
	}

	num_point = 0;

	for(int i = min_Y; i <= max_Y; i++){
		if(P[i].size() == 0)continue;

		sort(P[i].begin(),P[i].end());

		L[i] = num_point;
		point[num_point++] = P[i][0];

		for(int k = 1; k < P[i].size(); k++){

			R[i] = num_point;
			point[num_point++] = P[i][k];
		}
	}

	for(int i = 0; i < num_dog; i++){
		for(int k = 0; k < num_point; k++){
			if(input[first_S[i]] == point[k]){

				S[i] = k;
			}
			if(input[first_T[i]] == point[k]){

				T[i] = k;
			}
		}
	}

	for(int i = 0; i < num_point; i++){

		boss[i] = i;
		height[i] = i;
		L[i] = i;
		R[i] = i;
	}

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){

			if(k == i){

				min_dist[i][k] = 0;
			}else{

				min_dist[i][k] = BIG_NUM;
			}
		}
	}

	//エッジ張り
	for(int i = 0; i < num_point-1; i++){
		for(int k = i+1; k < num_point; k++){
			if(calc_dist(point[i],point[k]) > D+EPS)continue;

			bool FLG = true;
			Line tmp_line = Line(point[i],point[k]);
			for(int a = 0; a < num_point; a++){
				if(a == i || a == k)continue;

				if(getDistanceSP(tmp_line,point[a]) < EPS){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			if(point[i].Y == point[k].Y){

				unite(i,k);
				double tmp_dist = calc_dist(point[i],point[k]);
				G[i].push_back(Edge(k,tmp_dist));
				G[k].push_back(Edge(i,tmp_dist));

				min_dist[i][k] = tmp_dist;
				min_dist[k][i] = tmp_dist;
				//printf("%d-%dにエッジを張った\n",i,k);

			}else{

				int from = i;
				int to = k;
				if(point[i].Y > point[k].Y){

					swap(from,to);
				}
				G[from].push_back(Edge(to,calc_dist(point[i],point[k])));
				//printf("%d-%dにエッジを張った\n",from,to);
			}
		}
	}

	for(int mid = 0; mid < num_point; mid++){
		for(int start = 0; start < num_point; start++){
			if(fabs(min_dist[start][mid]-BIG_NUM) < EPS)continue;
			for(int goal = 0; goal < num_point; goal++){
				if(fabs(min_dist[mid][goal]-BIG_NUM) < EPS)continue;

				min_dist[start][goal] = min(min_dist[start][goal],min_dist[start][mid]+min_dist[mid][goal]);
			}
		}
	}

	if(num_dog == 1){

		func1();

	}else if(num_dog == 2){

		func2();

	}else{

		func3();
	}

	return 0;
}
accuracy: 0.25
time_ms: 550
memory_kb: 36808
final_rank: 14

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 105
#define SIZE2 10005

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
		X = 0;
		Y = 0;
	}

	Point(){
		x = y = 0.0;
		X = Y = 0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{
		return x != p.x? x < p.x: y < p.y;
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}

   	/*
	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/

	double x,y;
	int X,Y;
};

typedef Point Vector;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};



struct Edge{
	Edge(int arg_to,double arg_dist){
		to = arg_to;
		dist = arg_dist;
	}
	int to;
	double dist;
};

struct State{
	State(int arg_node_id,double arg_sum_dist){
		node_id = arg_node_id;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct State &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int node_id;
	double sum_dist;
};

struct Info2{
	Info2(){

		loc[0] = loc[1] = 0;
		sum_dist = 0;
	}
	Info2(int arg_loc0,int arg_loc1,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info2 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}

	int loc[2];
	double sum_dist;
};

struct Info3{
	Info3(){

		loc[0] = loc[1] = loc[2] = 0;
		sum_dist = 0;
	}
	Info3(int arg_loc0,int arg_loc1,int arg_loc2,double arg_sum_dist){
		loc[0] = arg_loc0;
		loc[1] = arg_loc1;
		loc[2] = arg_loc2;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info3 &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int loc[3];
	double sum_dist;
};

struct TWO{
	TWO(int arg_left,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_right;
	}
	int pos[2];
};

struct THREE{
	THREE(int arg_left,int arg_mid,int arg_right){
		pos[0] = arg_left;
		pos[1] = arg_mid;
		pos[2] = arg_right;
	}
	int pos[3];
};

struct Data{
	Data(int arg_p_id,int arg_loc_id){
		p_id = arg_p_id;
		loc_id = arg_loc_id;
	}
	bool operator<(const struct Data &arg) const{

		return p_id < arg.p_id;
	}

	int p_id,loc_id;
};


int N,num_dog;
int first_S[3],first_T[3];
int S[3],T[3];
int boss[SIZE],height[SIZE];
int L[SIZE],R[SIZE];
int num_point;
int min_Y,max_Y;
double D;
double dp[SIZE],dp2[SIZE][SIZE],dp3[SIZE][SIZE][SIZE];
double min_dist[SIZE][SIZE];
Point input[SIZE],point[SIZE];
vector<Point> P[SIZE2];
vector<Edge> G[SIZE];



int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		L[boss_y] = min(L[boss_y],L[boss_x]);
		R[boss_y] = max(R[boss_y],R[boss_x]);
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		L[boss_x] = min(L[boss_x],L[boss_y]);
		R[boss_x] = max(R[boss_x],R[boss_y]);

		boss[boss_y] = boss_x;
		height[x]++;
	}
}


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

void func1(){

	for(int i = 0; i < num_point; i++){

		dp[i] = BIG_NUM;
	}

	dp[S[0]] = 0;
	priority_queue<State> Q;

	Q.push(State(S[0],0));

	int next_node;
	double next_dist;

	while(!Q.empty()){

		if(Q.top().sum_dist > dp[Q.top().node_id]+EPS){

			Q.pop();
		}else if(Q.top().node_id == T[0]){

			printf("%.10lf\n",Q.top().sum_dist);
			return;

		}else{

			for(int i = 0; i < G[Q.top().node_id].size(); i++){

				next_node = G[Q.top().node_id][i].to;
				next_dist = Q.top().sum_dist+G[Q.top().node_id][i].dist;

				if(dp[next_node] > next_dist+EPS){
					dp[next_node] = next_dist;
					Q.push(State(next_node,next_dist));
				}
			}
			Q.pop();
		}
	}

	printf("-1\n");
}

vector<TWO> calc_pos2(int first_left,int first_right){

	vector<TWO> ret;
	int group_id = get_boss(first_left);

	for(int l = L[group_id]; l < first_right; l++){
		for(int r = max(l,first_left)+1; r < R[group_id]; r++){

			ret.push_back(TWO(l,r));
		}
	}

	return ret;
}

vector<THREE> calc_pos3(int first_left,int first_mid,int first_right){

	vector<THREE> ret;
	int group_id = get_boss(first_left);

	for(int l = L[group_id]; l < first_mid; l++){
		for(int m = max(l,first_left)+1; m < first_right; m++){
			for(int r = max(m,first_mid)+1; r < R[group_id]; r++){

				ret.push_back(THREE(l,m,r));
			}
		}
	}

	return ret;
}

void func2(){

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){
			dp2[i][k] = BIG_NUM;
		}
	}

	dp2[S[0]][S[1]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info2> Q[2];
	Q[CURRENT].push(Info2(S[0],S[1],0));

	while(true){

		while(!Q[CURRENT].empty()){

			Info2 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			if(info.sum_dist > dp2[info.loc[0]][info.loc[1]]+EPS){

				continue;

			}else{

				if(get_boss(info.loc[0]) != get_boss(info.loc[1])){

					if(point[info.loc[0]].Y <= point[info.loc[1]].Y){

						for(int i = 0; i < G[info.loc[0]].size(); i++){

							int next_node = G[info.loc[0]][i].to;
							if(next_node == info.loc[1])continue;
							double next_dist = info.sum_dist+G[info.loc[0]][i].dist;

							if(dp2[next_node][info.loc[1]] > next_dist+EPS){
								dp2[next_node][info.loc[1]] = next_dist;
								Q[NEXT].push(Info2(next_node,info.loc[1],next_dist));
							}
						}

					}else{

						for(int i = 0; i < G[info.loc[1]].size(); i++){

							int next_node = G[info.loc[1]][i].to;
							if(next_node == info.loc[0])continue;
							double next_dist = info.sum_dist+G[info.loc[1]][i].dist;

							if(dp2[info.loc[0]][next_node] > next_dist+EPS){
								dp2[info.loc[0]][next_node] = next_dist;
								Q[NEXT].push(Info2(info.loc[0],next_node,next_dist));
							}
						}
					}

				}else{ //同グループ

					vector<TWO> vec = calc_pos2(min(info.loc[0],info.loc[1]),max(info.loc[0],info.loc[1]));

					int next0,next1,dist0,dist1;

					for(int i = 0; i < vec.size(); i++){

						if(info.loc[0] < info.loc[1]){ //index順とXの大小は一致している

							next0 = vec[i].pos[0];
							next1 = vec[i].pos[1];

						}else{

							next0 = vec[i].pos[1];
							next1 = vec[i].pos[0];
						}

						dist0 = min_dist[info.loc[0]][next0];
						dist1 = min_dist[info.loc[1]][next1];

						double next_dist = info.sum_dist+dist0+dist1;


						if(dp2[next0][next1] > next_dist+EPS){
							dp2[next0][next1] = next_dist;
							//★★PQには突っ込まない★★
						}else{

							continue; //★★注意★★
						}

						int to_0,to_1;

						for(int a = 0; a < G[next0].size(); a++){

							to_0 = G[next0][a].to;
							if(point[info.loc[0]].Y == point[to_0].Y)continue;
							for(int b = 0; b < G[next1].size(); b++){
								to_1 = G[next1][b].to;
								if(point[info.loc[1]].Y == point[to_1].Y)continue;
								if(to_1 == to_0)continue;

								double tmp_dist = next_dist+G[next0][a].dist+G[next1][b].dist;
								if(dp2[to_0][to_1] > tmp_dist+EPS){
									dp2[to_0][to_1] = tmp_dist;
									Q[NEXT].push(Info2(to_0,to_1,tmp_dist));
								}
							}
						}
					}
				}
			}
		}

		if(Q[NEXT].size() == 0)break;

		swap(CURRENT,NEXT);
	}

	if(fabs(dp2[T[0]][T[1]]-BIG_NUM) < EPS){

		printf("-1\n");

	}else{

		printf("%.10lf\n",dp2[T[0]][T[1]]);
	}
}

void func3(){

	for(int a = 0; a < num_point; a++){
		for(int b = 0; b < num_point; b++){
			for(int c = 0; c < num_point; c++){

				dp3[a][b][c] = BIG_NUM;
			}
		}
	}

	dp3[S[0]][S[1]][S[2]] = 0;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info3> Q[2];
	Q[CURRENT].push(Info3(S[0],S[1],S[2],0));

	while(true){

		while(!Q[CURRENT].empty()){

			Info3 info = Q[CURRENT].top();
			Q[CURRENT].pop();

			int minimum = BIG_NUM;
			int num_minimum = 0;
			int max_index;

			for(int i = 0; i < 3; i++){

				if(minimum > point[info.loc[i]].Y){
					minimum = point[info.loc[i]].Y;
					num_minimum = 1;
				}else if(minimum == point[info.loc[i]].Y){

					num_minimum++;
				}else{

					max_index = i;
				}
			}

			if((num_minimum == 1) || (get_boss(info.loc[0]) != get_boss(info.loc[1]) && get_boss(info.loc[0]) != get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) != get_boss(info.loc[2]))){ //Yの最小値が1つ、または全てのグループが異なる

				int min_index;

				for(int i = 0; i < 3; i++){

					if(point[info.loc[i]].Y == minimum){
						min_index = i;
						break;
					}
				}

				//動くのは一匹だけ

				int next[3];
				for(int k = 0; k < 3; k++){

					next[k] = info.loc[k];
				}

				for(int i = 0; i < G[info.loc[min_index]].size(); i++){

					int next_node = G[info.loc[min_index]][i].to;
					double next_dist = info.sum_dist+G[info.loc[min_index]][i].dist;

					next[min_index] = next_node;

					if(dp3[next[0]][next[1]][next[2]] > next_dist+EPS){

						dp3[next[0]][next[1]][next[2]] = next_dist;
						Q[NEXT].push(Info3(next[0],next[1],next[2],next_dist));
					}
				}

			}else if(get_boss(info.loc[0]) == get_boss(info.loc[1]) && get_boss(info.loc[0]) == get_boss(info.loc[2]) &&
					get_boss(info.loc[1]) == get_boss(info.loc[2])){ //全てのグループが同じ


				vector<Data> data;
				for(int i = 0; i < 3; i++){

					data.push_back(Data(info.loc[i],i));
				}

				sort(data.begin(),data.end());

				vector<THREE> vec = calc_pos3(data[0].p_id,data[1].p_id,data[2].p_id);

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < vec.size(); i++){

					for(int k = 0; k < 3; k++){

						TMP[data[k].loc_id] = vec[i].pos[k];
						tmp_d[data[k].loc_id] = min_dist[info.loc[data[k].loc_id]][TMP[data[k].loc_id]];
					}

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

					}else{

						continue; //★★
					}

					int to_0,to_1,to_2;

					for(int a = 0; a < G[TMP[0]].size(); a++){
						to_0 = G[TMP[0]][a].to;
						if(point[to_0].Y == point[info.loc[0]].Y)continue;
						for(int b = 0; b < G[TMP[1]].size(); b++){
							to_1 = G[TMP[1]][b].to;
							if(point[to_1].Y == point[info.loc[1]].Y)continue;
							if(to_1 == to_0)continue;
							for(int c = 0; c < G[TMP[2]].size(); c++){
								to_2 = G[TMP[2]][c].to;
								if(point[to_2].Y == point[info.loc[2]].Y)continue;
								if(to_2 == to_0 || to_2 == to_1)continue;

								double tmp_dist = next_dist+G[TMP[0]][a].dist+G[TMP[1]][b].dist+G[TMP[2]][c].dist;

								if(dp3[to_0][to_1][to_2] > tmp_dist+EPS){
									dp3[to_0][to_1][to_2] = tmp_dist;
									Q[NEXT].push(Info3(to_0,to_1,to_2,tmp_dist));
								}
							}
						}
					}
				}

			}else{ //グループが1匹+2匹で、2匹が下方

				vector<Data> tmp_v;
				for(int i = 0; i < 3; i++){
					if(point[info.loc[i]].Y == minimum){

						tmp_v.push_back(Data(info.loc[i],i));
					}
				}

				sort(tmp_v.begin(),tmp_v.end());

				vector<TWO> vec = calc_pos2(tmp_v[0].p_id,tmp_v[1].p_id);

				int TMP[3];
				double tmp_d[3];

				for(int i = 0; i < 3; i++){
					TMP[i] = info.loc[i];
					tmp_d[i] = 0;
				}

				for(int i = 0; i < vec.size(); i++){

					for(int k = 0; k < 2; k++){

						TMP[tmp_v[k].loc_id] = vec[i].pos[k];
						tmp_d[tmp_v[k].loc_id] = min_dist[info.loc[tmp_v[k].loc_id]][TMP[tmp_v[k].loc_id]];
					}

					double next_dist = info.sum_dist+tmp_d[0]+tmp_d[1]+tmp_d[2];

					if(dp3[TMP[0]][TMP[1]][TMP[2]] > next_dist+EPS){

						dp3[TMP[0]][TMP[1]][TMP[2]] = next_dist;
						//★★PQには突っ込まない★★

					}else{

						continue; //★★
					}

					int to[3];
					for(int a = 0; a < 3; a++){

						to[a] = TMP[a];
					}

					for(int a = 0; a < G[tmp_v[0].loc_id].size(); a++){
						to[tmp_v[0].loc_id] = G[tmp_v[0].loc_id][a].to;
						if(point[to[tmp_v[0].loc_id]].Y == minimum)continue;
						if(to[tmp_v[0].loc_id] == max_index)continue;
						for(int b = 0; b < G[tmp_v[1].loc_id].size(); b++){
							to[tmp_v[1].loc_id] = G[tmp_v[1].loc_id][b].to;
							if(point[to[tmp_v[1].loc_id]].Y == minimum)continue;
							if(to[tmp_v[1].loc_id] == max_index || to[tmp_v[1].loc_id] == to[tmp_v[0].loc_id])continue;

							double tmp_dist = next_dist+G[tmp_v[0].loc_id][a].dist+G[tmp_v[1].loc_id][b].dist;

							if(dp3[to[0]][to[1]][to[2]] > tmp_dist+EPS){

								dp3[to[0]][to[1]][to[2]] = tmp_dist;
								Q[NEXT].push(Info3(to[0],to[1],to[2],tmp_dist));
							}
						}
					}
				}
			}
		}

		if(Q[NEXT].size() == 0)break;

		swap(CURRENT,NEXT);
	}

	if(fabs(dp3[T[0]][T[1]][T[2]]-BIG_NUM) < EPS){

		printf("-1\n");
	}else{

		printf("%.10lf\n",dp3[T[0]][T[1]][T[2]]);
	}
}

int main(){

	scanf("%d %d",&N,&num_dog);
	scanf("%lf",&D);

	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_S[i]);
		first_S[i]--;
	}
	for(int i = 0; i < num_dog; i++){

		scanf("%d",&first_T[i]);
		first_T[i]--;
	}

	min_Y = BIG_NUM,max_Y = -BIG_NUM;

	for(int i = 0; i < N; i++){

		scanf("%d %d",&input[i].X,&input[i].Y);
		input[i].x = input[i].X;
		input[i].y = input[i].Y;

		min_Y = min(min_Y,input[i].Y);
		max_Y = max(max_Y,input[i].Y);

		P[input[i].Y].push_back(input[i]);
	}

	num_point = 0;

	for(int i = min_Y; i <= max_Y; i++){
		if(P[i].size() == 0)continue;

		sort(P[i].begin(),P[i].end());

		L[i] = num_point;
		point[num_point++] = P[i][0];

		for(int k = 1; k < P[i].size(); k++){

			R[i] = num_point;
			point[num_point++] = P[i][k];
		}
	}

	for(int i = 0; i < num_dog; i++){
		for(int k = 0; k < num_point; k++){
			if(input[first_S[i]] == point[k]){

				S[i] = k;
			}
			if(input[first_T[i]] == point[k]){

				T[i] = k;
			}
		}
	}

	for(int i = 0; i < num_point; i++){

		boss[i] = i;
		height[i] = i;
		L[i] = i;
		R[i] = i;
	}

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < num_point; k++){

			if(k == i){

				min_dist[i][k] = 0;
			}else{

				min_dist[i][k] = BIG_NUM;
			}
		}
	}

	//エッジ張り
	for(int i = 0; i < num_point-1; i++){
		for(int k = i+1; k < num_point; k++){
			if(calc_dist(point[i],point[k]) > D+EPS)continue;

			bool FLG = true;
			Line tmp_line = Line(point[i],point[k]);
			for(int a = 0; a < num_point; a++){
				if(a == i || a == k)continue;

				if(getDistanceSP(tmp_line,point[a]) < EPS){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			if(point[i].Y == point[k].Y){

				unite(i,k);
				double tmp_dist = calc_dist(point[i],point[k]);
				G[i].push_back(Edge(k,tmp_dist));
				G[k].push_back(Edge(i,tmp_dist));

				min_dist[i][k] = tmp_dist;
				min_dist[k][i] = tmp_dist;

			}else{

				int from = i;
				int to = k;
				if(point[i].Y > point[k].Y){

					swap(from,to);
				}
				G[from].push_back(Edge(to,calc_dist(point[i],point[k])));
			}
		}
	}

	for(int mid = 0; mid < num_point; mid++){
		for(int start = 0; start < num_point; start++){
			if(fabs(min_dist[start][mid]-BIG_NUM) < EPS)continue;
			for(int goal = 0; goal < num_point; goal++){
				if(fabs(min_dist[mid][goal]-BIG_NUM) < EPS)continue;

				min_dist[start][goal] = min(min_dist[start][goal],min_dist[start][mid]+min_dist[mid][goal]);
			}
		}
	}

	if(num_dog == 1){

		func1();

	}else if(num_dog == 2){

		func2();

	}else{

		func3();
	}

	return 0;
}
accuracy: 0.03571428571428571
time_ms: 560
memory_kb: 36824
final_rank: 20

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define rep1(i,n) for(int i=1;i<=(int)(n);i++)
#define reps(i,s,n) for(int i=s;i<n+s;i++)
#define ireps(i,s,n) for(int i=s+n-1;i>=s;i--)
#define all(c) c.begin(),c.end()
#define pb push_back
#define fs first
#define sc second
#define show(x) cout << #x << " = " << x << endl
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)
using namespace std;
inline bool B(int t,int i){return (t>>i)&1;}
typedef double D;
int N,K,Y,s[3],t[3],x[102],y[102],oid[102];
vector<int> ys;
vector<int> y2id[102];			//ashed y -> ids
D R,e[102][102],inf=1e9,eps=1e-8;
void changeid(){
	int iv[102];
	rep(i,N) iv[oid[i]]=i;
	rep(i,K) s[i]=iv[s[i]],t[i]=iv[t[i]];
}
bool kon(int i,int j,int k){
	if(i>j) swap(i,j);
	if(k<i||j<k) return 0;
	int c=(y[k]-y[i])*(x[j]-x[i]) - (x[k]-x[i])*(y[j]-y[i]);
	return c==0;
}
D dp[102][102][102],ndp[102][102][102],tmp3[102][102][102],tmp2[102][102],tmp1[102];
int t3[8][3]={
	{2,1,0},
	{2,1,0},
	{2,1,0},
	{1,2,0},
	{0,2,1},
	{0,1,2},
	{0,1,2},
	{0,1,2}
};
D changeith(int a,int b,int c,int& na,int& nb,int& nc,int i,int ad,int o,int S){
	if(a>b) swap(a,b);
	if(b>c) swap(b,c);
	if(a>b) swap(a,b);
	int x=0;
	if(i==0) x=a;
	if(i==1) x=b;
	if(i==2) x=c;
	int nx=x+ad;
	if(nx==o-1||nx==o+S) return inf;
	D ret=e[x][nx];
	if(x==na) na+=ad;
	if(x==nb) nb+=ad;
	if(x==nc) nc+=ad;
	if(na==nb||nb==nc||nc==na) return inf;
	return ret;
}
void dothree(int y){
//	printf("dothree %d\n",y);
	vector<int> vc=y2id[y];
	int S=vc.size(),o=vc[0];
	rep(t,8){
		reps(i,o,S) reps(j,o,S) reps(k,o,S) tmp3[i][j][k]=dp[i][j][k];
		rep(i_,3){
			int i=t3[t][i_];			//i-th leftest move
			if(B(t,2-i)){		//right
				reps(a,o,S) reps(b,o,S) reps(c,o,S) if(a!=b&&b!=c&&a!=c){
					int na=a,nb=b,nc=c;
					D cost=changeith(a,b,c,na,nb,nc,i,1,o,S);
					chmin(tmp3[na][nb][nc],tmp3[a][b][c]+cost);
				}
			}else{			//left
				ireps(a,o,S) ireps(b,o,S) ireps(c,o,S) if(a!=b&&b!=c&&a!=c){
					int na=a,nb=b,nc=c;
					D cost=changeith(a,b,c,na,nb,nc,i,-1,o,S);
					chmin(tmp3[na][nb][nc],tmp3[a][b][c]+cost);
				}
			}
		}
		reps(i,o,S) reps(j,o,S) reps(k,o,S) chmin(ndp[i][j][k],tmp3[i][j][k]);
	}
}
int t2[4][2]={
	{1,0},
	{1,0},
	{1,0},
	{0,1}
};
D changeith2(int a,int b,int& na,int &nb,int i,int ad,int o,int S){
	if(a>b) swap(a,b);
	int x=0;
	if(i==0) x=a;
	if(i==1) x=b;
	int nx=x+ad;
	if(nx==o-1||nx==o+S) return inf;
	D ret=e[x][nx];
	if(x==na) na+=ad;
	if(x==nb) nb+=ad;
	if(na==nb) return inf;
	return ret;
}
void dotwo(int y){
//	printf("dotwo %d\n",y);
	vector<int> vc=y2id[y];
	int S=vc.size(),o=vc[0];
	{				//a: not y
		rep(t,4){
			rep(a,N){
				if(o<=a&&a<o+S) continue;
				reps(j,o,S) reps(k,o,S) tmp2[j][k]=dp[a][j][k];
				rep(i_,2){
					int i=t2[t][i_];			//i-th leftest move
					if(B(t,1-i)){		//right
						reps(b,o,S) reps(c,o,S) if(b!=c){
							int nb=b,nc=c;
							D cost=changeith2(b,c,nb,nc,i,1,o,S);
							chmin(tmp2[nb][nc],tmp2[b][c]+cost);
						}
					}else{			//left
						ireps(b,o,S) ireps(c,o,S) if(b!=c){
							int nb=b,nc=c;
							D cost=changeith2(b,c,nb,nc,i,-1,o,S);
							chmin(tmp2[nb][nc],tmp2[b][c]+cost);
						}
					}
				}
				reps(j,o,S) reps(k,o,S) chmin(ndp[a][j][k],tmp2[j][k]);
			}
		}
	}
	{				//b: not y
		rep(t,4){
			rep(b,N){
				if(o<=b&&b<o+S) continue;
				reps(j,o,S) reps(k,o,S) tmp2[j][k]=dp[j][b][k];
				rep(i_,2){
					int i=t2[t][i_];			//i-th leftest move
					if(B(t,1-i)){		//right
						reps(a,o,S) reps(c,o,S) if(a!=c){
							int na=a,nc=c;
							D cost=changeith2(a,c,na,nc,i,1,o,S);
							chmin(tmp2[na][nc],tmp2[a][c]+cost);
						}
					}else{			//left
						ireps(a,o,S) ireps(c,o,S) if(a!=c){
							int na=a,nc=c;
							D cost=changeith2(a,c,na,nc,i,-1,o,S);
							chmin(tmp2[na][nc],tmp2[a][c]+cost);
						}
					}
				}
				reps(j,o,S) reps(k,o,S) chmin(ndp[j][b][k],tmp2[j][k]);
			}
		}
	}
	{				//c: not y
		rep(t,4){
			rep(c,N){
				if(o<=c&&c<o+S) continue;
				reps(j,o,S) reps(k,o,S) tmp2[j][k]=dp[j][k][c];
				rep(i_,2){
					int i=t2[t][i_];			//i-th leftest move
					if(B(t,1-i)){		//right
						reps(a,o,S) reps(b,o,S) if(a!=b){
							int na=a,nb=b;
							D cost=changeith2(a,b,na,nb,i,1,o,S);
							chmin(tmp2[na][nb],tmp2[a][b]+cost);
						}
					}else{			//left
						ireps(a,o,S) ireps(b,o,S) if(a!=b){
							int na=a,nb=b;
							D cost=changeith2(a,b,na,nb,i,-1,o,S);
							chmin(tmp2[na][nb],tmp2[a][b]+cost);
						}
					}
				}
				reps(j,o,S) reps(k,o,S) chmin(ndp[j][k][c],tmp2[j][k]);
			}
		}
	}
}
void doone(int y){
	vector<int> vc=y2id[y];
	int S=vc.size(),o=vc[0];
	{
		rep(b,N) rep(c,N){
			if(o<=b&&b<o+S) continue;
			if(o<=c&&c<o+S) continue;
			reps(a,o,S) tmp1[a]=dp[a][b][c];
			reps(a,o,S) if(a+1!=o+S) chmin(tmp1[a+1],tmp1[a]+e[a][a+1]);
			ireps(a,o,S) if(a-1!=o-1) chmin(tmp1[a-1],tmp1[a]+e[a][a-1]);
			reps(a,o,S) chmin(ndp[a][b][c],tmp1[a]);
		}
	}
	{
		rep(a,N) rep(c,N){
			if(o<=a&&a<o+S) continue;
			if(o<=c&&c<o+S) continue;
			reps(b,o,S) tmp1[b]=dp[a][b][c];
			reps(b,o,S) if(b+1!=o+S) chmin(tmp1[b+1],tmp1[b]+e[b][b+1]);
			ireps(b,o,S) if(b-1!=o-1) chmin(tmp1[b-1],tmp1[b]+e[b][b-1]);
			reps(b,o,S) chmin(ndp[a][b][c],tmp1[b]);
		}
	}
	{
		rep(a,N) rep(b,N){
			if(o<=a&&a<o+S) continue;
			if(o<=b&&b<o+S) continue;
			reps(c,o,S) tmp1[c]=dp[a][b][c];
			reps(c,o,S) if(c+1!=o+S) chmin(tmp1[c+1],tmp1[c]+e[c][c+1]);
			ireps(c,o,S) if(c-1!=o-1) chmin(tmp1[c-1],tmp1[c]+e[c][c-1]);
			reps(c,o,S) chmin(ndp[a][b][c],tmp1[c]);
		}
	}
}
int main(){
	cin>>N>>K>>R;
	rep(i,K) cin>>s[i],s[i]--;
	rep(i,K) cin>>t[i],t[i]--;
	rep(i,N) cin>>x[i]>>y[i];
	while(K<3){
		x[N]=N,y[N]=10001;
		s[K]=N,t[K]=N;
		N++;
		K++;
	}
	rep(i,N) oid[i]=i;
	rep(i,N-1) rep(j,N-1) if( y[j]>y[j+1] || (y[j]==y[j+1]&&x[j]>x[j+1]) ) swap(x[j],x[j+1]),swap(y[j],y[j+1]),swap(oid[j],oid[j+1]);
	changeid();
//	rep(i,K) printf("s[%d],t[%d]=%d,%d\n",i,i,s[i],t[i]);
	rep(i,N) rep(j,N) if(i!=j){
		e[i][j]=sqrt( (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]) );
		if(e[i][j]>R+eps) e[i][j]=inf;
		rep(k,N) if(k!=i&&k!=j){
			if(kon(i,j,k)) e[i][j]=inf;
		}
	}
	rep(i,N) ys.pb(y[i]);
	sort(all(ys));
	ys.erase(unique(ys.begin(),ys.end()),ys.end());
	rep(i,N) y2id[ lower_bound(all(ys),y[i])-ys.begin() ].pb(i);
	Y=ys.size();
	rep(i,N) rep(j,N) rep(k,N) dp[i][j][k]=inf;
	dp[s[0]][s[1]][s[2]]=0;
	rep(yid,Y){
		rep(a,N) rep(b,N) rep(c,N) if(dp[a][b][c]<inf){			// a:<y -> y
			if(y[a]<ys[yid]){
				for(int n:y2id[yid]) if(n!=b&&n!=c) chmin(dp[n][b][c],dp[a][b][c]+e[a][n]);
			}
		}
		rep(a,N) rep(b,N) rep(c,N) if(dp[a][b][c]<inf){			// b:<y -> y
			if(y[b]<ys[yid]){
				for(int n:y2id[yid]) if(n!=a&&n!=c) chmin(dp[a][n][c],dp[a][b][c]+e[b][n]);
			}
		}
		rep(a,N) rep(b,N) rep(c,N) if(dp[a][b][c]<inf){			// c:<y -> y
			if(y[c]<ys[yid]){
				for(int n:y2id[yid]) if(n!=a&&n!=b) chmin(dp[a][b][n],dp[a][b][c]+e[c][n]);
			}
		}
		rep(a,N) rep(b,N) rep(c,N) ndp[a][b][c]=dp[a][b][c];
		dothree(yid);
		dotwo(yid);
		doone(yid);
		rep(a,N) rep(b,N) rep(c,N) dp[a][b][c]=ndp[a][b][c];
	}
	// rep(i,N) rep(j,N){
	// 	printf("e[%d][%d]=%lf\n",i,j,e[i][j]);
	// }
	// rep(i,N) rep(j,N) rep(k,N) if(dp[i][j][k]!=inf){
	// 	printf("dp[%d][%d][%d]=%f\n",i,j,k,dp[i][j][k]);
	// }
	D ans=dp[t[0]][t[1]][t[2]];
	if(ans==inf) ans=-1;
	printf("%.12f\n",ans);
}
accuracy: 1
time_ms: 680
memory_kb: 27660
final_rank: 4

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define rep1(i,n) for(int i=1;i<=(int)(n);i++)
#define reps(i,s,n) for(int i=s;i<n+s;i++)
#define ireps(i,s,n) for(int i=s+n-1;i>=s;i--)
#define all(c) c.begin(),c.end()
#define pb push_back
#define fs first
#define sc second
#define show(x) cout << #x << " = " << x << endl
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)
using namespace std;
inline bool B(int t,int i){return (t>>i)&1;}
typedef double D;
int N,K,Y,s[3],t[3],x[102],y[102],oid[102];
vector<int> ys;
vector<int> y2id[102];			//ashed y -> ids
D R,e[102][102],inf=1e9,eps=1e-8;
void changeid(){
	int iv[102];
	rep(i,N) iv[oid[i]]=i;
	rep(i,K) s[i]=iv[s[i]],t[i]=iv[t[i]];
}
bool kon(int i,int j,int k){
	if(i>j) swap(i,j);
	if(k<i||j<k) return 0;
	int c=(y[k]-y[i])*(x[j]-x[i]) - (x[k]-x[i])*(y[j]-y[i]);
	return c==0;
}
D dp[102][102][102],ndp[102][102][102],tmp3[102][102][102],tmp2[102][102],tmp1[102];
int t3[8][3]={
	{2,1,0},
	{2,1,0},
	{2,1,0},
	{1,2,0},
	{0,2,1},
	{0,1,2},
	{0,1,2},
	{0,1,2}
};
D changeith(int a,int b,int c,int& na,int& nb,int& nc,int i,int ad,int o,int S){
	if(a>b) swap(a,b);
	if(b>c) swap(b,c);
	if(a>b) swap(a,b);
	int x=0;
	if(i==0) x=a;
	if(i==1) x=b;
	if(i==2) x=c;
	int nx=x+ad;
	if(nx==o-1||nx==o+S) return inf;
	D ret=e[x][nx];
	if(x==na) na+=ad;
	if(x==nb) nb+=ad;
	if(x==nc) nc+=ad;
	if(na==nb||nb==nc||nc==na) return inf;
	return ret;
}
void dothree(int y){
//	printf("dothree %d\n",y);
	vector<int> vc=y2id[y];
	int S=vc.size(),o=vc[0];
	rep(t,8){
		reps(i,o,S) reps(j,o,S) reps(k,o,S) tmp3[i][j][k]=dp[i][j][k];
		rep(i_,3){
			int i=t3[t][i_];			//i-th leftest move
			if(B(t,2-i)){		//right
				reps(a,o,S) reps(b,o,S) reps(c,o,S) if(a!=b&&b!=c&&a!=c){
					int na=a,nb=b,nc=c;
					D cost=changeith(a,b,c,na,nb,nc,i,1,o,S);
					chmin(tmp3[na][nb][nc],tmp3[a][b][c]+cost);
				}
			}else{			//left
				ireps(a,o,S) ireps(b,o,S) ireps(c,o,S) if(a!=b&&b!=c&&a!=c){
					int na=a,nb=b,nc=c;
					D cost=changeith(a,b,c,na,nb,nc,i,-1,o,S);
					chmin(tmp3[na][nb][nc],tmp3[a][b][c]+cost);
				}
			}
		}
		reps(i,o,S) reps(j,o,S) reps(k,o,S) chmin(ndp[i][j][k],tmp3[i][j][k]);
	}
}
int t2[4][2]={
	{1,0},
	{1,0},
	{1,0},
	{0,1}
};
D changeith2(int a,int b,int& na,int &nb,int i,int ad,int o,int S){
	if(a>b) swap(a,b);
	int x=0;
	if(i==0) x=a;
	if(i==1) x=b;
	int nx=x+ad;
	if(nx==o-1||nx==o+S) return inf;
	D ret=e[x][nx];
	if(x==na) na+=ad;
	if(x==nb) nb+=ad;
	if(na==nb) return inf;
	return ret;
}
void dotwo(int y){
//	printf("dotwo %d\n",y);
	vector<int> vc=y2id[y];
	int S=vc.size(),o=vc[0];
	{				//a: not y
		rep(t,4){
			rep(a,N){
				if(o<=a&&a<o+S) continue;
				reps(j,o,S) reps(k,o,S) tmp2[j][k]=dp[a][j][k];
				rep(i_,2){
					int i=t2[t][i_];			//i-th leftest move
					if(B(t,1-i)){		//right
						reps(b,o,S) reps(c,o,S) if(b!=c){
							int nb=b,nc=c;
							D cost=changeith2(b,c,nb,nc,i,1,o,S);
							chmin(tmp2[nb][nc],tmp2[b][c]+cost);
						}
					}else{			//left
						ireps(b,o,S) ireps(c,o,S) if(b!=c){
							int nb=b,nc=c;
							D cost=changeith2(b,c,nb,nc,i,-1,o,S);
							chmin(tmp2[nb][nc],tmp2[b][c]+cost);
						}
					}
				}
				reps(j,o,S) reps(k,o,S) chmin(ndp[a][j][k],tmp2[j][k]);
			}
		}
	}
	{				//b: not y
		rep(t,4){
			rep(b,N){
				if(o<=b&&b<o+S) continue;
				reps(j,o,S) reps(k,o,S) tmp2[j][k]=dp[j][b][k];
				rep(i_,2){
					int i=t2[t][i_];			//i-th leftest move
					if(B(t,1-i)){		//right
						reps(a,o,S) reps(c,o,S) if(a!=c){
							int na=a,nc=c;
							D cost=changeith2(a,c,na,nc,i,1,o,S);
							chmin(tmp2[na][nc],tmp2[a][c]+cost);
						}
					}else{			//left
						ireps(a,o,S) ireps(c,o,S) if(a!=c){
							int na=a,nc=c;
							D cost=changeith2(a,c,na,nc,i,-1,o,S);
							chmin(tmp2[na][nc],tmp2[a][c]+cost);
						}
					}
				}
				reps(j,o,S) reps(k,o,S) chmin(ndp[j][b][k],tmp2[j][k]);
			}
		}
	}
	{				//c: not y
		rep(t,4){
			rep(c,N){
				if(o<=c&&c<o+S) continue;
				reps(j,o,S) reps(k,o,S) tmp2[j][k]=dp[j][k][c];
				rep(i_,2){
					int i=t2[t][i_];			//i-th leftest move
					if(B(t,1-i)){		//right
						reps(a,o,S) reps(b,o,S) if(a!=b){
							int na=a,nb=b;
							D cost=changeith2(a,b,na,nb,i,1,o,S);
							chmin(tmp2[na][nb],tmp2[a][b]+cost);
						}
					}else{			//left
						ireps(a,o,S) ireps(b,o,S) if(a!=b){
							int na=a,nb=b;
							D cost=changeith2(a,b,na,nb,i,-1,o,S);
							chmin(tmp2[na][nb],tmp2[a][b]+cost);
						}
					}
				}
				reps(j,o,S) reps(k,o,S) chmin(ndp[j][k][c],tmp2[j][k]);
			}
		}
	}
}
void doone(int y){
	vector<int> vc=y2id[y];
	int S=vc.size(),o=vc[0];
	{
		rep(b,N) rep(c,N){
			if(o<=b&&b<o+S) continue;
			if(o<=c&&c<o+S) continue;
			reps(a,o,S) tmp1[a]=dp[a][b][c];
			reps(a,o,S) if(a+1!=o+S) chmin(tmp1[a+1],tmp1[a]+e[a][a+1]);
			ireps(a,o,S) if(a-1!=o-1) chmin(tmp1[a-1],tmp1[a]+e[a][a-1]);
			reps(a,o,S) chmin(ndp[a][b][c],tmp1[a]);
		}
	}
	{
		rep(a,N) rep(c,N){
			if(o<=a&&a<o+S) continue;
			if(o<=c&&c<o+S) continue;
			reps(b,o,S) tmp1[b]=dp[a][b][c];
			reps(b,o,S) if(b+1!=o+S) chmin(tmp1[b+1],tmp1[b]+e[b][b+1]);
			ireps(b,o,S) if(b-1!=o-1) chmin(tmp1[b-1],tmp1[b]+e[b][b-1]);
			reps(b,o,S) chmin(ndp[a][b][c],tmp1[b]);
		}
	}
	{
		rep(a,N) rep(b,N){
			if(o<=a&&a<o+S) continue;
			if(o<=b&&b<o+S) continue;
			reps(c,o,S) tmp1[c]=dp[a][b][c];
			reps(c,o,S) if(c+1!=o+S) chmin(tmp1[c+1],tmp1[c]+e[c][c+1]);
			ireps(c,o,S) if(c-1!=o-1) chmin(tmp1[c-1],tmp1[c]+e[c][c-1]);
			reps(c,o,S) chmin(ndp[a][b][c],tmp1[c]);
		}
	}
}
int main(){
	cin>>N>>K>>R;
	rep(i,K) cin>>s[i],s[i]--;
	rep(i,K) cin>>t[i],t[i]--;
	rep(i,N) cin>>x[i]>>y[i];
	while(K<3){
		x[N]=N,y[N]=10001;
		s[K]=N,t[K]=N;
		N++;
		K++;
	}
	rep(i,N) oid[i]=i;
	rep(i,N-1) rep(j,N-1) if( y[j]>y[j+1] || (y[j]==y[j+1]&&x[j]>x[j+1]) ) swap(x[j],x[j+1]),swap(y[j],y[j+1]),swap(oid[j],oid[j+1]);
	changeid();
	rep(i,N) rep(j,N) if(i!=j){
		e[i][j]=sqrt( (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]) );
		if(e[i][j]>R+eps) e[i][j]=inf;
		rep(k,N) if(k!=i&&k!=j){
			if(kon(i,j,k)) e[i][j]=inf;
		}
	}
	rep(i,N) ys.pb(y[i]);
	sort(all(ys));
	ys.erase(unique(ys.begin(),ys.end()),ys.end());
	rep(i,N) y2id[ lower_bound(all(ys),y[i])-ys.begin() ].pb(i);
	Y=ys.size();
	rep(i,N) rep(j,N) rep(k,N) dp[i][j][k]=inf;
	dp[s[0]][s[1]][s[2]]=0;
	rep(yid,Y){
		rep(a,N) rep(b,N) rep(c,N) if(dp[a][b][c]<inf){			// a:<y -> y
			if(y[a]<ys[yid]){
				for(int n:y2id[yid]) chmin(dp[n][b][c],dp[a][b][c]+e[a][n]);
			}
		}
		rep(a,N) rep(b,N) rep(c,N) if(dp[a][b][c]<inf){			// b:<y -> y
			if(y[b]<ys[yid]){
				for(int n:y2id[yid]) chmin(dp[a][n][c],dp[a][b][c]+e[b][n]);
			}
		}
		rep(a,N) rep(b,N) rep(c,N) if(dp[a][b][c]<inf){			// c:<y -> y
			if(y[c]<ys[yid]){
				for(int n:y2id[yid]) chmin(dp[a][b][n],dp[a][b][c]+e[c][n]);
			}
		}
		rep(a,N) rep(b,N) rep(c,N) ndp[a][b][c]=dp[a][b][c];
		dothree(yid);
		dotwo(yid);
		doone(yid);
		rep(a,N) rep(b,N) rep(c,N) dp[a][b][c]=ndp[a][b][c];
	}
	// rep(i,N) rep(j,N){
	// 	printf("e[%d][%d]=%lf\n",i,j,e[i][j]);
	// }
	// rep(i,N) rep(j,N) rep(k,N) if(dp[i][j][k]!=inf){
	// 	printf("dp[%d][%d][%d]=%f\n",i,j,k,dp[i][j][k]);
	// }
	D ans=dp[t[0]][t[1]][t[2]];
	if(ans==inf) ans=-1;
	printf("%.12f\n",ans);
}
accuracy: 0.5357142857142857
time_ms: 670
memory_kb: 27420
final_rank: 11

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define rep1(i,n) for(int i=1;i<=(int)(n);i++)
#define reps(i,s,n) for(int i=s;i<n+s;i++)
#define ireps(i,s,n) for(int i=s+n-1;i>=s;i--)
#define all(c) c.begin(),c.end()
#define pb push_back
#define fs first
#define sc second
#define show(x) cout << #x << " = " << x << endl
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)
using namespace std;
inline bool B(int t,int i){return (t>>i)&1;}
typedef double D;
int N,K,Y,s[3],t[3],x[102],y[102],oid[102];
vector<int> ys;
vector<int> y2id[102];			//ashed y -> ids
D R,e[102][102],inf=1e9,eps=1e-8;
void changeid(){
	int iv[102];
	rep(i,N) iv[oid[i]]=i;
	rep(i,K) s[i]=iv[s[i]],t[i]=iv[t[i]];
}
bool kon(int i,int j,int k){
	if(i>j) swap(i,j);
	if(k<i||j<k) return 0;
	int c=(y[k]-y[i])*(x[j]-x[i]) - (x[k]-x[i])*(y[j]-y[i]);
	return c==0;
}
D dp[102][102][102],ndp[102][102][102],tmp3[102][102][102],tmp2[102][102],tmp1[102];
int t3[8][3]={
	{2,1,0},
	{2,1,0},
	{2,1,0},
	{1,2,0},
	{0,2,1},
	{0,1,2},
	{0,1,2},
	{0,1,2}
};
D changeith(int a,int b,int c,int& na,int& nb,int& nc,int i,int ad,int o,int S){
	if(a>b) swap(a,b);
	if(b>c) swap(b,c);
	if(a>b) swap(a,b);
	int x=0;
	if(i==0) x=a;
	if(i==1) x=b;
	if(i==2) x=c;
	int nx=x+ad;
	if(nx==o-1||nx==o+S) return inf;
	D ret=e[x][nx];
	if(x==na) na+=ad;
	if(x==nb) nb+=ad;
	if(x==nc) nc+=ad;
	if(na==nb||nb==nc||nc==na) return inf;
	return ret;
}
void dothree(int y){
//	printf("dothree %d\n",y);
	vector<int> vc=y2id[y];
	int S=vc.size(),o=vc[0];
	rep(t,8){
		reps(i,o,S) reps(j,o,S) reps(k,o,S) tmp3[i][j][k]=dp[i][j][k];
		rep(i_,3){
			int i=t3[t][i_];			//i-th leftest move
			if(B(t,2-i)){		//right
				reps(a,o,S) reps(b,o,S) reps(c,o,S) if(a!=b&&b!=c&&a!=c){
					int na=a,nb=b,nc=c;
					D cost=changeith(a,b,c,na,nb,nc,i,1,o,S);
					chmin(tmp3[na][nb][nc],tmp3[a][b][c]+cost);
				}
			}else{			//left
				ireps(a,o,S) ireps(b,o,S) ireps(c,o,S) if(a!=b&&b!=c&&a!=c){
					int na=a,nb=b,nc=c;
					D cost=changeith(a,b,c,na,nb,nc,i,-1,o,S);
					chmin(tmp3[na][nb][nc],tmp3[a][b][c]+cost);
				}
			}
		}
		reps(i,o,S) reps(j,o,S) reps(k,o,S) chmin(ndp[i][j][k],tmp3[i][j][k]);
	}
}
int t2[4][2]={
	{1,0},
	{1,0},
	{1,0},
	{0,1}
};
D changeith2(int a,int b,int& na,int &nb,int i,int ad,int o,int S){
	if(a>b) swap(a,b);
	int x=0;
	if(i==0) x=a;
	if(i==1) x=b;
	int nx=x+ad;
	if(nx==o-1||nx==o+S) return inf;
	D ret=e[x][nx];
	if(x==na) na+=ad;
	if(x==nb) nb+=ad;
	if(na==nb) return inf;
	return ret;
}
void dotwo(int y){
//	printf("dotwo %d\n",y);
	vector<int> vc=y2id[y];
	int S=vc.size(),o=vc[0];
	{				//a: not y
		rep(t,4){
			rep(a,N){
				if(o<=a&&a<o+S) continue;
				reps(j,o,S) reps(k,o,S) tmp2[j][k]=dp[a][j][k];
				rep(i_,2){
					int i=t2[t][i_];			//i-th leftest move
					if(B(t,1-i)){		//right
						reps(b,o,S) reps(c,o,S) if(b!=c){
							int nb=b,nc=c;
							D cost=changeith2(b,c,nb,nc,i,1,o,S);
							chmin(tmp2[nb][nc],tmp2[b][c]+cost);
						}
					}else{			//left
						ireps(b,o,S) ireps(c,o,S) if(b!=c){
							int nb=b,nc=c;
							D cost=changeith2(b,c,nb,nc,i,-1,o,S);
							chmin(tmp2[nb][nc],tmp2[b][c]+cost);
						}
					}
				}
				reps(j,o,S) reps(k,o,S) chmin(ndp[a][j][k],tmp2[j][k]);
			}
		}
	}
	{				//b: not y
		rep(t,4){
			rep(b,N){
				if(o<=b&&b<o+S) continue;
				reps(j,o,S) reps(k,o,S) tmp2[j][k]=dp[j][b][k];
				rep(i_,2){
					int i=t2[t][i_];			//i-th leftest move
					if(B(t,1-i)){		//right
						reps(a,o,S) reps(c,o,S) if(a!=c){
							int na=a,nc=c;
							D cost=changeith2(a,c,na,nc,i,1,o,S);
							chmin(tmp2[na][nc],tmp2[a][c]+cost);
						}
					}else{			//left
						ireps(a,o,S) ireps(c,o,S) if(a!=c){
							int na=a,nc=c;
							D cost=changeith2(a,c,na,nc,i,-1,o,S);
							chmin(tmp2[na][nc],tmp2[a][c]+cost);
						}
					}
				}
				reps(j,o,S) reps(k,o,S) chmin(ndp[j][b][k],tmp2[j][k]);
			}
		}
	}
	{				//c: not y
		rep(t,4){
			rep(c,N){
				if(o<=c&&c<o+S) continue;
				reps(j,o,S) reps(k,o,S) tmp2[j][k]=dp[j][k][c];
				rep(i_,2){
					int i=t2[t][i_];			//i-th leftest move
					if(B(t,1-i)){		//right
						reps(a,o,S) reps(b,o,S) if(a!=b){
							int na=a,nb=b;
							D cost=changeith2(a,b,na,nb,i,1,o,S);
							chmin(tmp2[na][nb],tmp2[a][b]+cost);
						}
					}else{			//left
						ireps(a,o,S) ireps(b,o,S) if(a!=b){
							int na=a,nb=b;
							D cost=changeith2(a,b,na,nb,i,-1,o,S);
							chmin(tmp2[na][nb],tmp2[a][b]+cost);
						}
					}
				}
				reps(j,o,S) reps(k,o,S) chmin(ndp[j][k][c],tmp2[j][k]);
			}
		}
	}
}
void doone(int y){
	vector<int> vc=y2id[y];
	int S=vc.size(),o=vc[0];
	{
		rep(b,N) rep(c,N){
			if(o<=b&&b<o+S) continue;
			if(o<=c&&c<o+S) continue;
			reps(a,o,S) tmp1[a]=dp[a][b][c];
			reps(a,o,S) if(a+1!=o+S) chmin(tmp1[a+1],tmp1[a]+e[a][a+1]);
			ireps(a,o,S) if(a-1!=o-1) chmin(tmp1[a-1],tmp1[a]+e[a][a-1]);
			reps(a,o,S) chmin(ndp[a][b][c],tmp1[a]);
		}
	}
	{
		rep(a,N) rep(c,N){
			if(o<=a&&a<o+S) continue;
			if(o<=c&&c<o+S) continue;
			reps(b,o,S) tmp1[b]=dp[a][b][c];
			reps(b,o,S) if(b+1!=o+S) chmin(tmp1[b+1],tmp1[b]+e[b][b+1]);
			ireps(b,o,S) if(b-1!=o-1) chmin(tmp1[b-1],tmp1[b]+e[b][b-1]);
			reps(b,o,S) chmin(ndp[a][b][c],tmp1[b]);
		}
	}
	{
		rep(a,N) rep(b,N){
			if(o<=a&&a<o+S) continue;
			if(o<=b&&b<o+S) continue;
			reps(c,o,S) tmp1[c]=dp[a][b][c];
			reps(c,o,S) if(c+1!=o+S) chmin(tmp1[c+1],tmp1[c]+e[c][c+1]);
			ireps(c,o,S) if(c-1!=o-1) chmin(tmp1[c-1],tmp1[c]+e[c][c-1]);
			reps(c,o,S) chmin(ndp[a][b][c],tmp1[c]);
		}
	}
}
int main(){
	cin>>N>>K>>R;
	rep(i,K) cin>>s[i],s[i]--;
	rep(i,K) cin>>t[i],t[i]--;
	rep(i,N) cin>>x[i]>>y[i];
	while(K<3){
		x[N]=N,y[N]=10001;
		s[K]=N,t[K]=N;
		N++;
		K++;
	}
	rep(i,N) oid[i]=i;
	rep(i,N-1) rep(j,N-1) if( y[j]>y[j+1] || (y[j]==y[j+1]&&x[j]>x[j+1]) ) swap(x[j],x[j+1]),swap(y[j],y[j+1]),swap(oid[j],oid[j+1]);
	changeid();
	rep(i,N) rep(j,N) if(i!=j){
		e[i][j]=sqrt( (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]) );
		if(e[i][j]>R+eps) e[i][j]=inf;
		rep(k,N) if(k!=i&&k!=j){
			if(kon(i,j,k)) e[i][j]=inf;
		}
	}
	rep(i,N) ys.pb(y[i]);
	sort(all(ys));
	ys.erase(unique(ys.begin(),ys.end()),ys.end());
	rep(i,N) y2id[ lower_bound(all(ys),y[i])-ys.begin() ].pb(i);
	Y=ys.size();
	rep(i,N) rep(j,N) rep(k,N) dp[i][j][k]=inf;
	dp[s[0]][s[1]][s[2]]=0;
	rep(yid,Y){
		rep(a,N) rep(b,N) rep(c,N) if(dp[a][b][c]<inf){			// a:<y -> y
			if(y[a]<ys[yid]){
				for(int n:y2id[yid]) chmin(dp[n][b][c],dp[a][b][c]+e[a][n]);
			}
		}
		rep(a,N) rep(b,N) rep(c,N) if(dp[a][b][c]<inf){			// b:<y -> y
			if(y[b]<ys[yid]){
				for(int n:y2id[yid]) chmin(dp[a][n][c],dp[a][b][c]+e[b][n]);
			}
		}
		rep(a,N) rep(b,N) rep(c,N) if(dp[a][b][c]<inf){			// c:<y -> y
			if(y[c]<ys[yid]){
				for(int n:y2id[yid]) chmin(dp[a][b][n],dp[a][b][c]+e[c][n]);
			}
		}
		rep(a,N) rep(b,N) rep(c,N) ndp[a][b][c]=dp[a][b][c];
		dothree(yid);
		dotwo(yid);
		doone(yid);
		rep(a,N) rep(b,N) rep(c,N) dp[a][b][c]=ndp[a][b][c];
	}
	// rep(i,N) rep(j,N){
	// 	printf("e[%d][%d]=%lf\n",i,j,e[i][j]);
	// }
	// rep(i,N) rep(j,N) rep(k,N) if(dp[i][j][k]!=inf){
	// 	printf("dp[%d][%d][%d]=%f\n",i,j,k,dp[i][j][k]);
	// }
	printf("%.12f\n",dp[t[0]][t[1]][t[2]]);
}
accuracy: 0.10714285714285714
time_ms: 670
memory_kb: 19936
final_rank: 17

code_snippet: #include<cstdio>
#include<queue>
#include<utility>
#include<cmath>
#include<algorithm>

using namespace std;

typedef pair<int,int> P;
typedef pair<P,int> PP;
typedef pair<double,PP> State;
typedef pair<State,bool> State2;

const double inf=1e9;
const double eps=1e-6;
const double eps2=1e-9;

P ps[110];
int N;
bool ok[110][110];

int ss[3],ts[3];
double R;

double getDis(int i,int j){
	if(i==ts[0]&&j==N-3) return 0;
	if(i==ts[1]&&j==N-2) return 0;
	if(i==ts[2]&&j==N-1) return 0;
	int dx=ps[i].first-ps[j].first;
	int dy=ps[i].second-ps[j].second;
	return sqrt(dx*dx+dy*dy);
}

//priority_queue<State,vector<State>,greater<State> > que;
priority_queue<State2,vector<State2>,greater<State2> > que;
double dp[110][110][110][2];

State getState(double a,int i,int j,int k){
	State res;
	res.first=a;
	res.second.first.first=i;
	res.second.first.second=j;
	res.second.second=k;
	return res;
}

State2 getState2(double a,int i,int j,int k,bool flg){
	State st=getState(a,i,j,k);
	return make_pair(st,flg);
}

bool check(int i,int j,int k){
	if(i>=N-3&&i!=N-3) return false;
	if(j>=N-3&&j!=N-2) return false;
	if(k>=N-3&&k!=N-1) return false;
	return true;
}

int lb[110],ub[110];
bool flg[110][110][110];

void trans2(State2 st2){
	State st=st2.first;
	double cur=st.first;
	int i=st.second.first.first;
	int j=st.second.first.second;
	int k=st.second.second;
	if(dp[i][j][k][0]<cur) return;
//	if(i>j&&j>k&&max(max(i,j),k)<N-3) printf("%f %d %d %d\n",cur,i,j,k);
	P tmp[]={P(i,0),P(j,1),P(k,2)};
	sort(tmp,tmp+3);
	if(ps[tmp[0].first]!=ps[tmp[2].first]){
		int l=lb[tmp[0].first];
		int r=ub[tmp[0].first];
		for(int x=l;x<=min(r,tmp[1].first-1);x++){
			for(int y=max(x+1,tmp[0].first+1);y<=r;y++){
				double add_dis=getDis(tmp[0].first,x)+getDis(tmp[1].first,y);
				double nxt=cur+add_dis;
				int ids[]={-1,-1,-1};
				ids[tmp[0].second]=x;
				ids[tmp[1].second]=y;
				ids[tmp[2].second]=tmp[2].first;
				if(dp[ids[0]][ids[1]][ids[2]][0]<nxt+eps2) continue;
				if(check(ids[0],ids[1],ids[2])==false) continue;
				dp[ids[0]][ids[1]][ids[2]][0]=nxt;
				flg[ids[0]][ids[1]][ids[2]]=true;
				que.push(getState2(nxt,ids[0],ids[1],ids[2],false));
			}
		}
	}else{
		int l=lb[tmp[0].first];
		int r=ub[tmp[0].first];
		for(int x=l;x<=min(r,tmp[1].first-1);x++){
			for(int y=max(l,tmp[0].first+1);y<=min(r,tmp[2].first-1);y++){
				for(int z=max(l,tmp[1].first);z<=r;z++){
					double add_dis=getDis(tmp[0].first,x)+getDis(tmp[1].first,y)+getDis(tmp[2].first,z);
					double nxt=cur+add_dis;
					int ids[]={-1,-1,-1};
					ids[tmp[0].second]=x;
					ids[tmp[1].second]=y;
					ids[tmp[2].second]=z;
					if(dp[ids[0]][ids[1]][ids[2]][0]<nxt+eps2) continue;
					if(check(ids[0],ids[1],ids[2])==false) continue;
					dp[ids[0]][ids[1]][ids[2]][0]=nxt;
					flg[ids[0]][ids[1]][ids[2]]=true;
					que.push(getState2(nxt,ids[0],ids[1],ids[2],false));
				}
			}
		}
	}
}


void trans(State2 st2){
	State st=st2.first;
	double cur=st.first;
	int i=st.second.first.first;
	int j=st.second.first.second;
	int k=st.second.second;
	int which=st2.second?1:0;
	if(dp[i][j][k][which]<cur) return;
//	printf("%f %d %d %d\n",cur,i,j,k);
	int tmp[]={i,j,k};
	sort(tmp,tmp+3);
	if(ps[tmp[0]].second==ps[tmp[1]].second&&st2.second==0){
		if(flg[i][j][k]==false) trans2(st2);
	}
	if(ps[i].second==ps[tmp[0]].second){
		for(int ni=i+1;ni<N;ni++){
			if(ok[i][ni]&&ps[i].second!=ps[ni].second){
				if(ni==j||ni==k) continue;
				double nxt=cur+getDis(i,ni);
			/*	int nwhich=0;
				for(int id=0;id<3;id++){
					if(ps[tmp[id]].second==ps[ni].second) nwhich=1;
				}
				if(same_exist) nwhich=1;*/
				int nwhich=(ps[i].second==ps[j].second||ps[i].second==ps[k].second)?1:0;
				if(dp[ni][j][k][nwhich]<nxt+eps2) continue;
				if(check(ni,j,k)==false) continue;
				dp[ni][j][k][nwhich]=nxt;
				que.push(getState2(nxt,ni,j,k,(nwhich==1)));
			}
		}
	}
	if(ps[j].second==ps[tmp[0]].second){
		for(int nj=j+1;nj<N;nj++){
			if(ok[j][nj]&&ps[j].second!=ps[nj].second){
				if(nj==i||nj==k) continue;
				double nxt=cur+getDis(j,nj);/*
				int nwhich=0;
				for(int id=0;id<3;id++){
					if(ps[tmp[id]].second==ps[nj].second) nwhich=1;
				}
				if(same_exist) nwhich=1;*/
				int nwhich=(ps[j].second==ps[i].second||ps[j].second==ps[k].second)?1:0;
				if(dp[i][nj][k][nwhich]<nxt+eps2) continue;
				if(check(i,nj,k)==false) continue;
				dp[i][nj][k][nwhich]=nxt;
				que.push(getState2(nxt,i,nj,k,(nwhich==1)));
			}
		}
	}
	if(ps[k].second==ps[tmp[0]].second){
		for(int nk=k+1;nk<N;nk++){
			if(ok[k][nk]&&ps[k].second!=ps[nk].second){
				if(nk==i||nk==j) continue;
				double nxt=cur+getDis(k,nk);
				/*int nwhich=0;
				for(int id=0;id<3;id++){
					if(ps[tmp[id]].second==ps[nk].second) nwhich=1;
				}
				if(same_exist) nwhich=1;*/
				int nwhich=(ps[k].second==ps[i].second||ps[k].second==ps[j].second)?1:0;
				if(dp[i][j][nk][nwhich]<nxt+eps2) continue;
				if(check(i,j,nk)==false) continue;
				dp[i][j][nk][nwhich]=nxt;
				que.push(getState2(nxt,i,j,nk,nwhich==1));
			}
		}
	}
	if(which==0){
		int mi=min(min(i,j),k);
		int le=lb[mi],ri=ub[mi];
		int cnt=0;
		if(ps[mi].second==ps[i].second) cnt++;
		if(ps[mi].second==ps[j].second) cnt++;
		if(ps[mi].second==ps[k].second) cnt++;
		if(cnt>=2) return;
		for(int n=le;n<=ri;n++){
			if(mi==i){
				if(n==i) continue;
				double nxt=dp[i][j][k][0]+getDis(n,i);
				if(dp[n][j][k][0]<nxt+eps2) continue;
				if(check(n,j,k)==false) continue;
				dp[n][j][k][0]=nxt;
				que.push(getState2(nxt,n,j,k,0));
			}else if(mi==j){
				if(n==j) continue;
				double nxt=dp[i][j][k][0]+getDis(n,j);
				if(dp[i][n][k][0]<nxt+eps2) continue;
				if(check(i,n,k)==false) continue;
				dp[i][n][k][0]=nxt;
				que.push(getState2(nxt,i,n,k,0));
			}else{
				if(n==k) continue;
				double nxt=dp[i][j][k][0]+getDis(n,k);
				if(dp[i][j][n][0]<nxt+eps2) continue;
				if(check(i,j,n)==false) continue;
				dp[i][j][n][0]=nxt;
				que.push(getState2(nxt,i,j,n,0));
			}
		}
	}
}

void dijkstra(){
	for(int i=0;i<N;i++) for(int j=0;j<N;j++) for(int k=0;k<N;k++){
		for(int t=0;t<2;t++){
			dp[i][j][k][t]=inf;
		}
	}
	int which=0;
	/*for(int i=0;i<3;i++) for(int j=i+1;j<3;j++){
		if(ps[ss[i]].second==ps[ss[j]].second) which=1;
	}*/
	dp[ss[0]][ss[1]][ss[2]][which]=0;
	que.push(getState2(0,ss[0],ss[1],ss[2],which));
	while(!que.empty()){
		State2 st2=que.top();
		que.pop();
		trans(st2);
	}
}

bool check_can_go(int i,int j){
	if(i==ts[0]&&j==N-3) return true;
	if(i==ts[1]&&j==N-2) return true;
	if(i==ts[2]&&j==N-1) return true;
	if(j>=N-3) return false;
	int dx=ps[i].first-ps[j].first;
	int dy=ps[i].second-ps[j].second;
	if(dx*dx+dy*dy>R*R+eps) return false;
	for(int k=0;k<N;k++){
		int dx1=ps[i].first-ps[k].first;
		int dy1=ps[i].second-ps[k].second;
		int dx2=ps[j].second-ps[k].second;
		int dy2=ps[j].second-ps[k].second;
		if(dx1*dy2==dx2*dy1&&dx1*dx2+dy1*dy2<0) return false;
	}
	return true;
}

int xs[110],ys[110];
PP rock_ids[110];
int s_[3],t_[3];
int K;

void precalc(){
	for(int i=K;i<=2;i++){
		xs[N]=i;
		ys[N]=10100;
		N++;
		xs[N]=i;
		ys[N]=10101;
		N++;
		s_[i]=N-2;
		t_[i]=N-1;
	}
	for(int i=0;i<3;i++){
		xs[N+i]=i;
		ys[N+i]=12000;
	}
	N+=3;
	for(int i=0;i<N;i++){
		rock_ids[i]=PP(P(ys[i],xs[i]),i);
	}
	sort(rock_ids,rock_ids+N);
	for(int i=0;i<N;i++){
		ps[i]=rock_ids[i].first;
		swap(ps[i].first,ps[i].second);
		for(int k=0;k<3;k++){
			int id=rock_ids[i].second;
			if(id==s_[k]) ss[k]=i;
			if(id==t_[k]) ts[k]=i;
		}
	}
	lb[0]=0;
	for(int i=1;i<N;i++){
		if(ps[i].second==ps[i-1].second) lb[i]=lb[i-1];
		else lb[i]=i;
	}
	ub[N-1]=N-1;
	for(int i=N-2;i>=0;i--){
		if(ps[i].second==ps[i+1].second) ub[i]=ub[i+1];
		else ub[i]=i;
	}
	for(int i=0;i<N;i++) for(int j=0;j<N;j++){
		ok[i][j]=check_can_go(i,j);
	}
	ok[ts[0]][N-3]=true;
	ok[ts[1]][N-2]=true;
	ok[ts[2]][N-1]=true;
}

int main(){
	scanf("%d%d",&N,&K);
	scanf("%lf",&R);
	for(int i=0;i<K;i++){
		scanf("%d",s_+i);
		s_[i]--;
	}
	for(int i=0;i<K;i++){
		scanf("%d",t_+i);
		t_[i]--;
	}
	for(int i=0;i<N;i++){
		scanf("%d%d",xs+i,ys+i);
	}
	precalc();
	dijkstra();
	double ans=dp[N-3][N-2][N-1][0];
	if(ans<inf/2) printf("%.9f\n",ans-(3-K));
	else printf("-1\n");
	return 0;
}
accuracy: 0.35714285714285715
time_ms: 1710
memory_kb: 53380
final_rank: 12

code_snippet: #include<cstdio>
#include<queue>
#include<utility>
#include<cmath>
#include<algorithm>

using namespace std;

typedef pair<int,int> P;
typedef pair<P,int> PP;
typedef pair<double,PP> State;
typedef pair<State,bool> State2;

const double inf=1e9;
const double eps=1e-6;
const double eps2=1e-9;

P ps[110];
int N;
bool ok[110][110];

int ss[3],ts[3];
double R;

double getDis(int i,int j){
	if(i==ts[0]&&j==N-3) return 0;
	if(i==ts[1]&&j==N-2) return 0;
	if(i==ts[2]&&j==N-1) return 0;
	int dx=ps[i].first-ps[j].first;
	int dy=ps[i].second-ps[j].second;
	return sqrt(dx*dx+dy*dy);
}

//priority_queue<State,vector<State>,greater<State> > que;
priority_queue<State2,vector<State2>,greater<State2> > que;
double dp[110][110][110][2];

State getState(double a,int i,int j,int k){
	State res;
	res.first=a;
	res.second.first.first=i;
	res.second.first.second=j;
	res.second.second=k;
	return res;
}

State2 getState2(double a,int i,int j,int k,bool flg){
	State st=getState(a,i,j,k);
	return make_pair(st,flg);
}

bool check(int i,int j,int k){
	if(i>=N-3&&i!=N-3) return false;
	if(j>=N-3&&j!=N-2) return false;
	if(k>=N-3&&k!=N-1) return false;
	return true;
}

int lb[110],ub[110];
bool flg[110][110][110];

void trans2(State2 st2){
	State st=st2.first;
	double cur=st.first;
	int i=st.second.first.first;
	int j=st.second.first.second;
	int k=st.second.second;
	if(dp[i][j][k][0]<cur) return;
//	if(i>j&&j>k&&max(max(i,j),k)<N-3) printf("%f %d %d %d\n",cur,i,j,k);
	P tmp[]={P(i,0),P(j,1),P(k,2)};
	sort(tmp,tmp+3);
	if(ps[tmp[0].first]!=ps[tmp[2].first]){
		int l=lb[tmp[0].first];
		int r=ub[tmp[0].first];
		for(int x=l;x<=min(r,tmp[1].first-1);x++){
			for(int y=max(x+1,tmp[0].first+1);y<=r;y++){
				double add_dis=getDis(tmp[0].first,x)+getDis(tmp[1].first,y);
				double nxt=cur+add_dis;
				int ids[]={-1,-1,-1};
				ids[tmp[0].second]=x;
				ids[tmp[1].second]=y;
				ids[tmp[2].second]=tmp[2].first;
				if(dp[ids[0]][ids[1]][ids[2]][0]<nxt+eps2) continue;
				if(check(ids[0],ids[1],ids[2])==false) continue;
				dp[ids[0]][ids[1]][ids[2]][0]=nxt;
				flg[ids[0]][ids[1]][ids[2]]=true;
				que.push(getState2(nxt,ids[0],ids[1],ids[2],false));
			}
		}
	}else{
		int l=lb[tmp[0].first];
		int r=ub[tmp[0].first];
		for(int x=l;x<=min(r,tmp[1].first-1);x++){
			for(int y=max(l,tmp[0].first+1);y<=min(r,tmp[2].first-1);y++){
				for(int z=max(l,tmp[1].first);z<=r;z++){
					double add_dis=getDis(tmp[0].first,x)+getDis(tmp[1].first,y)+getDis(tmp[2].first,z);
					double nxt=cur+add_dis;
					int ids[]={-1,-1,-1};
					ids[tmp[0].second]=x;
					ids[tmp[1].second]=y;
					ids[tmp[2].second]=z;
					if(dp[ids[0]][ids[1]][ids[2]][0]<nxt+eps2) continue;
					if(check(ids[0],ids[1],ids[2])==false) continue;
					dp[ids[0]][ids[1]][ids[2]][0]=nxt;
					flg[ids[0]][ids[1]][ids[2]]=true;
					que.push(getState2(nxt,ids[0],ids[1],ids[2],false));
				}
			}
		}
	}
}


void trans(State2 st2){
	State st=st2.first;
	double cur=st.first;
	int i=st.second.first.first;
	int j=st.second.first.second;
	int k=st.second.second;
	int which=st2.second?1:0;
	if(dp[i][j][k][which]<cur) return;
//	printf("%f %d %d %d\n",cur,i,j,k);
	int tmp[]={i,j,k};
	sort(tmp,tmp+3);
	bool same_exist=false;
	if(ps[tmp[0]].second==ps[tmp[1]].second){
		same_exist=true;
		if(flg[i][j][k]==false) trans2(st2);
	}
	if(ps[i].second==ps[tmp[0]].second){
		for(int ni=i+1;ni<N;ni++){
			if(ok[i][ni]&&ps[i].second!=ps[ni].second){
				if(ni==j||ni==k) continue;
				double nxt=cur+getDis(i,ni);
			/*	int nwhich=0;
				for(int id=0;id<3;id++){
					if(ps[tmp[id]].second==ps[ni].second) nwhich=1;
				}
				if(same_exist) nwhich=1;*/
				int nwhich=(ps[i].second==ps[j].second||ps[i].second==ps[k].second)?1:0;
				if(dp[ni][j][k][nwhich]<nxt+eps2) continue;
				if(check(ni,j,k)==false) continue;
				dp[ni][j][k][nwhich]=nxt;
				que.push(getState2(nxt,ni,j,k,(nwhich==1)));
			}
		}
	}
	if(ps[j].second==ps[tmp[0]].second){
		for(int nj=j+1;nj<N;nj++){
			if(ok[j][nj]&&ps[j].second!=ps[nj].second){
				if(nj==i||nj==k) continue;
				double nxt=cur+getDis(j,nj);/*
				int nwhich=0;
				for(int id=0;id<3;id++){
					if(ps[tmp[id]].second==ps[nj].second) nwhich=1;
				}
				if(same_exist) nwhich=1;*/
				int nwhich=(ps[j].second==ps[i].second||ps[j].second==ps[k].second)?1:0;
				if(dp[i][nj][k][nwhich]<nxt+eps2) continue;
				if(check(i,nj,k)==false) continue;
				dp[i][nj][k][nwhich]=nxt;
				que.push(getState2(nxt,i,nj,k,(nwhich==1)));
			}
		}
	}
	if(ps[k].second==ps[tmp[0]].second){
		for(int nk=k+1;nk<N;nk++){
			if(ok[k][nk]&&ps[k].second!=ps[nk].second){
				if(nk==i||nk==j) continue;
				double nxt=cur+getDis(k,nk);
				/*int nwhich=0;
				for(int id=0;id<3;id++){
					if(ps[tmp[id]].second==ps[nk].second) nwhich=1;
				}
				if(same_exist) nwhich=1;*/
				int nwhich=(ps[k].second==ps[i].second||ps[k].second==ps[j].second)?1:0;
				if(dp[i][j][nk][nwhich]<nxt+eps2) continue;
				if(check(i,j,nk)==false) continue;
				dp[i][j][nk][nwhich]=nxt;
				que.push(getState2(nxt,i,j,nk,nwhich==1));
			}
		}
	}
	if(which==0){
		int mi=min(min(i,j),k);
		int le=lb[mi],ri=ub[mi];
		for(int n=le;n<=ri;n++){
			if(mi==i){
				if(n==i) continue;
				double nxt=dp[i][j][k][0]+getDis(n,i);
				if(dp[n][j][k][0]<nxt+eps2) continue;
				if(check(n,j,k)==false) continue;
				dp[n][j][k][0]=nxt;
				que.push(getState2(nxt,n,j,k,0));
			}else if(mi==j){
				if(n==j) continue;
				double nxt=dp[i][j][k][0]+getDis(n,j);
				if(dp[i][n][k][0]<nxt+eps2) continue;
				if(check(i,n,k)==false) continue;
				dp[i][n][k][0]=nxt;
				que.push(getState2(nxt,i,n,k,0));
			}else{
				if(n==k) continue;
				double nxt=dp[i][j][k][0]+getDis(n,k);
				if(dp[i][j][n][0]<nxt+eps2) continue;
				if(check(i,j,n)==false) continue;
				dp[i][j][n][0]=nxt;
				que.push(getState2(nxt,i,j,n,0));
			}
		}
	}
}

void dijkstra(){
	for(int i=0;i<N;i++) for(int j=0;j<N;j++) for(int k=0;k<N;k++){
		for(int t=0;t<2;t++){
			dp[i][j][k][t]=inf;
		}
	}
	int which=0;
	/*for(int i=0;i<3;i++) for(int j=i+1;j<3;j++){
		if(ps[ss[i]].second==ps[ss[j]].second) which=1;
	}*/
	dp[ss[0]][ss[1]][ss[2]][which]=0;
	que.push(getState2(0,ss[0],ss[1],ss[2],which));
	while(!que.empty()){
		State2 st2=que.top();
		que.pop();
		trans(st2);
	}
}

bool check_can_go(int i,int j){
	if(i==ts[0]&&j==N-3) return true;
	if(i==ts[1]&&j==N-2) return true;
	if(i==ts[2]&&j==N-1) return true;
	if(j>=N-3) return false;
	int dx=ps[i].first-ps[j].first;
	int dy=ps[i].second-ps[j].second;
	if(dx*dx+dy*dy>R*R+eps) return false;
	for(int k=0;k<N;k++){
		int dx1=ps[i].first-ps[k].first;
		int dy1=ps[i].second-ps[k].second;
		int dx2=ps[j].second-ps[k].second;
		int dy2=ps[j].second-ps[k].second;
		if(dx1*dy2==dx2*dy1&&dx1*dx2+dy1*dy2<0) return false;
	}
	return true;
}

int xs[110],ys[110];
PP rock_ids[110];
int s_[3],t_[3];
int K;

void precalc(){
	for(int i=K;i<=2;i++){
		xs[N]=i;
		ys[N]=10100;
		N++;
		xs[N]=i;
		ys[N]=10101;
		N++;
		s_[i]=N-2;
		t_[i]=N-1;
	}
	for(int i=0;i<3;i++){
		xs[N+i]=i;
		ys[N+i]=12000;
	}
	N+=3;
	for(int i=0;i<N;i++){
		rock_ids[i]=PP(P(ys[i],xs[i]),i);
	}
	sort(rock_ids,rock_ids+N);
	for(int i=0;i<N;i++){
		ps[i]=rock_ids[i].first;
		swap(ps[i].first,ps[i].second);
		for(int k=0;k<3;k++){
			int id=rock_ids[i].second;
			if(id==s_[k]) ss[k]=i;
			if(id==t_[k]) ts[k]=i;
		}
	}
	lb[0]=0;
	for(int i=1;i<N;i++){
		if(ps[i].second==ps[i-1].second) lb[i]=lb[i-1];
		else lb[i]=i;
	}
	ub[N-1]=N-1;
	for(int i=N-2;i>=0;i--){
		if(ps[i].second==ps[i+1].second) ub[i]=ub[i+1];
		else ub[i]=i;
	}
	for(int i=0;i<N;i++) for(int j=0;j<N;j++){
		ok[i][j]=check_can_go(i,j);
	}
	ok[ts[0]][N-3]=true;
	ok[ts[1]][N-2]=true;
	ok[ts[2]][N-1]=true;
}

int main(){
	scanf("%d%d",&N,&K);
	scanf("%lf",&R);
	for(int i=0;i<K;i++){
		scanf("%d",s_+i);
		s_[i]--;
	}
	for(int i=0;i<K;i++){
		scanf("%d",t_+i);
		t_[i]--;
	}
	for(int i=0;i<N;i++){
		scanf("%d%d",xs+i,ys+i);
	}
	precalc();
	dijkstra();
	double ans=dp[N-3][N-2][N-1][0];
	if(ans<inf/2) printf("%.9f\n",ans-(3-K));
	else printf("-1\n");
	return 0;
}
accuracy: 0.17857142857142858
time_ms: 1730
memory_kb: 54736
final_rank: 16

code_snippet: #include<cstdio>
#include<queue>
#include<utility>
#include<cmath>
#include<algorithm>

using namespace std;

typedef pair<int,int> P;
typedef pair<P,int> PP;
typedef pair<double,PP> State;
typedef pair<State,bool> State2;

const double inf=1e9;
const double eps=1e-6;
const double eps2=1e-9;

P ps[110];
int N;
bool ok[110][110];

int ss[3],ts[3];
double R;

double getDis(int i,int j){
	if(i==ts[0]&&j==N-3) return 0;
	if(i==ts[1]&&j==N-2) return 0;
	if(i==ts[2]&&j==N-1) return 0;
	int dx=ps[i].first-ps[j].first;
	int dy=ps[i].second-ps[j].second;
	return sqrt(dx*dx+dy*dy);
}

//priority_queue<State,vector<State>,greater<State> > que;
priority_queue<State2,vector<State2>,greater<State2> > que;
double dp[110][110][110][2];

State getState(double a,int i,int j,int k){
	State res;
	res.first=a;
	res.second.first.first=i;
	res.second.first.second=j;
	res.second.second=k;
	return res;
}

State2 getState2(double a,int i,int j,int k,bool flg){
	State st=getState(a,i,j,k);
	return make_pair(st,flg);
}

int lb[110],ub[110];
bool flg[110][110][110];

void trans2(State2 st2){
	State st=st2.first;
	double cur=st.first;
	int i=st.second.first.first;
	int j=st.second.first.second;
	int k=st.second.second;
	if(dp[i][j][k][1]<cur) return;
	P tmp[]={P(i,0),P(j,1),P(k,2)};
	sort(tmp,tmp+3);
	if(ps[tmp[0].first]!=ps[tmp[2].first]){
		int l=lb[tmp[0].first];
		int r=ub[tmp[0].first];
		for(int x=l;x<=min(r,tmp[1].first-1);x++){
			for(int y=max(x+1,tmp[0].first+1);y<=r;y++){
				double add_dis=getDis(tmp[0].first,x)+getDis(tmp[1].first,y);
				double nxt=cur+add_dis;
				int ids[]={-1,-1,-1};
				ids[tmp[0].second]=x;
				ids[tmp[1].second]=y;
				ids[tmp[2].second]=tmp[2].first;
				if(dp[ids[0]][ids[1]][ids[2]][1]<nxt+eps2) continue;
				dp[ids[0]][ids[1]][ids[2]][1]=nxt;
				flg[ids[0]][ids[1]][ids[2]]=true;
				que.push(getState2(nxt,ids[0],ids[1],ids[2],true));
			}
		}
	}else{
		int l=lb[tmp[0].first];
		int r=ub[tmp[0].first];
		for(int x=l;x<=min(r,tmp[1].first-1);x++){
			for(int y=max(l,tmp[0].first+1);y<=min(r,tmp[2].first-1);y++){
				for(int z=max(l,tmp[1].first);z<=r;z++){
					double add_dis=getDis(tmp[0].first,x)+getDis(tmp[1].first,y)+getDis(tmp[2].first,z);
					double nxt=cur+add_dis;
					int ids[]={-1,-1,-1};
					ids[tmp[0].second]=x;
					ids[tmp[1].second]=y;
					ids[tmp[2].second]=z;
					if(dp[ids[0]][ids[1]][ids[2]][1]<nxt+eps2) continue;
					dp[ids[0]][ids[1]][ids[2]][1]=nxt;
					flg[ids[0]][ids[1]][ids[2]]=true;
					que.push(getState2(nxt,ids[0],ids[1],ids[2],true));
				}
			}
		}
	}
}


void trans(State2 st2){
	State st=st2.first;
	double cur=st.first;
	int i=st.second.first.first;
	int j=st.second.first.second;
	int k=st.second.second;
	int which=st2.second?1:0;
	if(dp[i][j][k][which]<cur) return;
	int tmp[]={i,j,k};
	sort(tmp,tmp+3);
	bool same_exist=false;
	if(ps[tmp[0]].second==ps[tmp[1]].second){
		same_exist=true;
		if(flg[i][j][k]==false) trans2(st2);
	}
	if(ps[i].second==ps[tmp[0]].second){
		for(int ni=i+1;ni<N;ni++){
			if(ok[i][ni]&&ps[i].second!=ps[ni].second){
				if(ni==j||ni==k) continue;
				double nxt=cur+getDis(i,ni);
				int nwhich=0;
				for(int id=0;id<3;id++){
					if(ps[tmp[id]].second==ps[ni].second) nwhich=1;
				}
				if(same_exist) nwhich=1;
				if(dp[ni][j][k][nwhich]<nxt+eps2) continue;
				dp[ni][j][k][nwhich]=nxt;
				que.push(getState2(nxt,ni,j,k,(nwhich==1)));
			}
		}
	}
	if(ps[j].second==ps[tmp[0]].second){
		for(int nj=j+1;nj<N;nj++){
			if(ok[j][nj]&&ps[j].second!=ps[nj].second){
				if(nj==i||nj==k) continue;
				double nxt=cur+getDis(j,nj);
				int nwhich=0;
				for(int id=0;id<3;id++){
					if(ps[tmp[id]].second==ps[nj].second) nwhich=1;
				}
				if(same_exist) nwhich=1;
				if(dp[i][nj][k][nwhich]<nxt+eps2) continue;
				dp[i][nj][k][nwhich]=nxt;
				que.push(getState2(nxt,i,nj,k,(nwhich==1)));
			}
		}
	}
	if(ps[k].second==ps[tmp[0]].second){
		for(int nk=k+1;nk<N;nk++){
			if(ok[k][nk]&&ps[k].second!=ps[nk].second){
				if(nk==i||nk==j) continue;
				double nxt=cur+getDis(k,nk);
				int nwhich=0;
				for(int id=0;id<3;id++){
					if(ps[tmp[id]].second==ps[nk].second) nwhich=1;
				}
				if(same_exist) nwhich=1;
				if(dp[i][j][nk][nwhich]<nxt+eps2) continue;
				dp[i][j][nk][nwhich]=nxt;
				que.push(getState2(nxt,i,j,nk,nwhich==1));
			}
		}
	}
	if(which==0){
		int mi=min(min(i,j),k);
		int le=lb[mi],ri=ub[mi];
		for(int n=le;n<=ri;n++){
			if(mi==i){
				if(n==i) continue;
				double nxt=dp[i][j][k][0]+getDis(n,i);
				if(dp[n][j][k][0]<nxt+eps2) continue;
				dp[n][j][k][0]=nxt;
				que.push(getState2(nxt,n,j,k,0));
			}else if(mi==j){
				if(n==j) continue;
				double nxt=dp[i][j][k][0]+getDis(n,j);
				if(dp[i][n][k][0]<nxt+eps2) continue;
				dp[i][n][k][0]=nxt;
				que.push(getState2(nxt,i,n,k,0));
			}else{
				if(n==k) continue;
				double nxt=dp[i][j][k][0]+getDis(n,k);
				if(dp[i][j][n][0]<nxt+eps2) continue;
				dp[i][j][n][0]=nxt;
				que.push(getState2(nxt,i,j,n,0));
			}
		}
	}
}

void dijkstra(){
	for(int i=0;i<N;i++) for(int j=0;j<N;j++) for(int k=0;k<N;k++){
		for(int t=0;t<2;t++){
			dp[i][j][k][t]=inf;
		}
	}
	int which=0;
	for(int i=0;i<3;i++) for(int j=i+1;j<3;j++){
		if(ps[ss[i]].second==ps[ss[j]].second) which=1;
	}
	dp[ss[0]][ss[1]][ss[2]][which]=0;
	que.push(getState2(0,ss[0],ss[1],ss[2],which));
	while(!que.empty()){
		State2 st2=que.top();
		que.pop();
		trans(st2);
	}
}

bool check_can_go(int i,int j){
	int dx=ps[i].first-ps[j].first;
	int dy=ps[i].second-ps[j].second;
	if(dx*dx+dy*dy>R*R+eps) return false;
	for(int k=0;k<N;k++){
		int dx1=ps[i].first-ps[k].first;
		int dy1=ps[i].second-ps[k].second;
		int dx2=ps[j].second-ps[k].second;
		int dy2=ps[j].second-ps[k].second;
		if(dx1*dy2==dx2*dy1&&dx1*dx2+dy1*dy2<0) return false;
	}
}

int xs[110],ys[110];
PP rock_ids[110];
int s_[3],t_[3];
int K;

void precalc(){
	for(int i=K;i<=2;i++){
		xs[N]=i;
		ys[N]=10100;
		N++;
		xs[N]=i;
		ys[N]=10101;
		N++;
		s_[i]=N-2;
		t_[i]=N-1;
	}
	for(int i=0;i<3;i++){
		xs[N+i]=i;
		ys[N+i]=12000;
	}
	N+=3;
	for(int i=0;i<N;i++){
		rock_ids[i]=PP(P(ys[i],xs[i]),i);
	}
	sort(rock_ids,rock_ids+N);
	for(int i=0;i<N;i++){
		ps[i]=rock_ids[i].first;
		swap(ps[i].first,ps[i].second);
		for(int k=0;k<3;k++){
			int id=rock_ids[i].second;
			if(id==s_[k]) ss[k]=i;
			if(id==t_[k]) ts[k]=i;
		}
	}
	lb[0]=0;
	for(int i=1;i<N;i++){
		if(ps[i].second==ps[i-1].second) lb[i]=lb[i-1];
		else lb[i]=i;
	}
	ub[N-1]=N-1;
	for(int i=N-2;i>=0;i--){
		if(ps[i].second==ps[i+1].second) ub[i]=ub[i+1];
		else ub[i]=i;
	}
	for(int i=0;i<N;i++) for(int j=0;j<N;j++){
		ok[i][j]=check_can_go(i,j);
	}
	ok[ts[0]][N-3]=true;
	ok[ts[1]][N-2]=true;
	ok[ts[2]][N-1]=true;
}

int main(){
	scanf("%d%d",&N,&K);
	scanf("%lf",&R);
	for(int i=0;i<K;i++){
		scanf("%d",s_+i);
		s_[i]--;
	}
	for(int i=0;i<K;i++){
		scanf("%d",t_+i);
		t_[i]--;
	}
	for(int i=0;i<N;i++){
		scanf("%d%d",xs+i,ys+i);
	}
	precalc();
	dijkstra();
	double ans=dp[N-3][N-2][N-1][1];
	if(ans<inf/2) printf("%.9f\n",ans-(3-K));
	else printf("-1\n");
	return 0;
}
accuracy: 0.32142857142857145
time_ms: 1930
memory_kb: 53196
final_rank: 13

code_snippet: #include<cstdio>
#include<queue>
#include<utility>
#include<cmath>
#include<algorithm>

using namespace std;

typedef pair<int,int> P;
typedef pair<P,int> PP;
typedef pair<double,PP> State;

const double inf=1e9;
const double eps=1e-6;
const double eps2=1e-9;

P ps[110];
int N;
bool ok[110][110];//when y coordinate differ

int ss[3],ts[3];
double R;

double getDis(int i,int j){
	if(i==ts[0]&&j==N-3) return 0;
	if(i==ts[1]&&j==N-2) return 0;
	if(i==ts[2]&&j==N-1) return 0;
	int dx=ps[i].first-ps[j].first;
	int dy=ps[i].second-ps[j].second;
	return sqrt(dx*dx+dy*dy);
}

priority_queue<State,vector<State>,greater<State> > que;
double dp[110][110][110];

//State::State(double a,int i,int j,int k):first(a),second.first.first(i),second.first.second(j),second.second(k){}

State getState(double a,int i,int j,int k){
	State res;
	res.first=a;
	res.second.first.first=i;
	res.second.first.second=j;
	res.second.second=k;
	return res;
}

int lb[110],ub[110];
bool flg[110][110][110];

void trans2(State st){
//	printf("trans2\n");
	double cur=st.first;
	int i=st.second.first.first;
	int j=st.second.first.second;
	int k=st.second.second;
	if(dp[i][j][k]<cur) return;
	P tmp[]={P(i,0),P(j,1),P(k,2)};
	sort(tmp,tmp+3);
	if(ps[tmp[0].first]!=ps[tmp[2].first]){
		int l=lb[tmp[0].first];
		int r=ub[tmp[0].first];
		for(int x=l;x<=min(r,tmp[1].first-1);x++){
			for(int y=max(x+1,tmp[0].first+1);y<=r;y++){
				double add_dis=getDis(tmp[0].first,x)+getDis(tmp[1].first,y);
				double nxt=cur+add_dis;
				int ids[]={-1,-1,-1};
				ids[tmp[0].second]=x;
				ids[tmp[1].second]=y;
				ids[tmp[2].second]=tmp[2].first;
				if(dp[ids[0]][ids[1]][ids[2]]<nxt+eps2) continue;
				dp[ids[0]][ids[1]][ids[2]]=nxt;
				flg[ids[0]][ids[1]][ids[2]]=true;
				que.push(getState(nxt,ids[0],ids[1],ids[2]));
			}
		}
	}else{
		int l=lb[tmp[0].first];
		int r=ub[tmp[0].first];
		for(int x=l;x<=min(r,tmp[1].first-1);x++){
			for(int y=max(l,tmp[0].first+1);y<=min(r,tmp[2].first-1);y++){
				for(int z=max(l,tmp[1].first);z<=r;z++){
					double add_dis=getDis(tmp[0].first,x)+getDis(tmp[1].first,y)+getDis(tmp[2].first,z);
					double nxt=cur+add_dis;
					int ids[]={-1,-1,-1};
					ids[tmp[0].second]=x;
					ids[tmp[1].second]=y;
					ids[tmp[2].second]=z;
					if(dp[ids[0]][ids[1]][ids[2]]<nxt+eps2) continue;
					dp[ids[0]][ids[1]][ids[2]]=nxt;
					flg[ids[0]][ids[1]][ids[2]]=true;
					que.push(getState(nxt,ids[0],ids[1],ids[2]));
				}
			}
		}
	}
}


void trans(State st){
	double cur=st.first;
	int i=st.second.first.first;
	int j=st.second.first.second;
	int k=st.second.second;
//	printf("%f %d %d %d\n", cur,i,j,k);
	if(dp[i][j][k]<cur) return;
	int tmp[]={i,j,k};
	sort(tmp,tmp+3);
//	for(int i=0;i<3;i++) printf("%d ",tmp[i]);
//	printf("\n");
	if(ps[tmp[0]].second==ps[tmp[1]].second){
		//printf("a\n");
		if(flg[i][j][k]==false) trans2(st);
	}
	if(ps[i].second==ps[tmp[0]].second){
		for(int ni=i+1;ni<N;ni++){
			if(ok[i][ni]&&ps[i].second!=ps[ni].second){
				if(ni==j||ni==k) continue;
				double nxt=cur+getDis(i,ni);
				if(dp[ni][j][k]<nxt+eps2) continue;
				dp[ni][j][k]=nxt;
				que.push(getState(nxt,ni,j,k));
			}
		}
	}
	if(ps[j].second==ps[tmp[0]].second){
		for(int nj=j+1;nj<N;nj++){
			if(ok[j][nj]&&ps[j].second!=ps[nj].second){
				if(nj==i||nj==k) continue;
				double nxt=cur+getDis(j,nj);
				if(dp[i][nj][k]<nxt+eps2) continue;
				dp[i][nj][k]=nxt;
				que.push(getState(nxt,i,nj,k));
			}
		}
	}
	if(ps[k].second==ps[tmp[0]].second){
		for(int nk=k+1;nk<N;nk++){
			if(ok[k][nk]&&ps[k].second!=ps[nk].second){
				if(nk==i||nk==j) continue;
				double nxt=cur+getDis(k,nk);
				if(dp[i][j][nk]<nxt+eps2) continue;
				dp[i][j][nk]=nxt;
				que.push(getState(nxt,i,j,nk));
			}
		}
	}
}

void dijkstra(){
	for(int i=0;i<N;i++) for(int j=0;j<N;j++) for(int k=0;k<N;k++) dp[i][j][k]=inf;
	dp[ss[0]][ss[1]][ss[2]]=0;
	que.push(getState(0,ss[0],ss[1],ss[2]));
	while(!que.empty()){
		State st=que.top();
		que.pop();
		trans(st);
	}
}

bool check_can_go(int i,int j){
	int dx=ps[i].first-ps[j].first;
	int dy=ps[i].second-ps[j].second;
	if(dx*dx+dy*dy>R*R+eps) return false;
	for(int k=0;k<N;k++){
		int dx1=ps[i].first-ps[k].first;
		int dy1=ps[i].second-ps[k].second;
		int dx2=ps[j].second-ps[k].second;
		int dy2=ps[j].second-ps[k].second;
		if(dx1*dy2==dx2*dy1&&dx1*dx2+dy1*dy2<0) return false;
	}
}

int xs[110],ys[110];
PP rock_ids[110];
int s_[3],t_[3];
int K;

void precalc(){
	for(int i=K;i<=2;i++){
		xs[N]=i;
		ys[N]=10100;
		N++;
		xs[N]=i;
		ys[N]=10101;
		N++;
		s_[i]=N-2;
		t_[i]=N-1;
	}
	for(int i=0;i<3;i++){
		xs[N+i]=i;
		ys[N+i]=12000;
	}
	N+=3;
	for(int i=0;i<N;i++){
		rock_ids[i]=PP(P(ys[i],xs[i]),i);
	}
	sort(rock_ids,rock_ids+N);
	for(int i=0;i<N;i++){
		ps[i]=rock_ids[i].first;
		swap(ps[i].first,ps[i].second);
		for(int k=0;k<3;k++){
			int id=rock_ids[i].second;
			if(id==s_[k]) ss[k]=i;
			if(id==t_[k]) ts[k]=i;
		}
	}
	lb[0]=0;
	for(int i=1;i<N;i++){
		if(ps[i].second==ps[i-1].second) lb[i]=lb[i-1];
		else lb[i]=i;
	}
	ub[N-1]=N-1;
	for(int i=N-2;i>=0;i--){
		if(ps[i].second==ps[i+1].second) ub[i]=ub[i+1];
		else ub[i]=i;
	}
	for(int i=0;i<N;i++) for(int j=0;j<N;j++){
		ok[i][j]=check_can_go(i,j);
	}
	ok[ts[0]][N-3]=true;
	ok[ts[1]][N-2]=true;
	ok[ts[2]][N-1]=true;
/*	for(int i=0;i<N;i++){
		printf("%d %d\n",ps[i].first,ps[i].second);
	}
	for(int i=0;i<3;i++){
		printf("%d %d\n",ss[i],ts[i]);
	}*/
}

int main(){
	scanf("%d%d",&N,&K);
	scanf("%lf",&R);
	for(int i=0;i<K;i++){
		scanf("%d",s_+i);
		s_[i]--;
	}
	for(int i=0;i<K;i++){
		scanf("%d",t_+i);
		t_[i]--;
	}
	for(int i=0;i<N;i++){
		scanf("%d%d",xs+i,ys+i);
	}
	precalc();
//	for(int i=0;i<10;i++) printf("%d %d\n",ps[i].first,ps[i].second);
	dijkstra();
//	double ans=dp[ts[0]][ts[1]][ts[2]];
/*	for(int i=0;i<10;i++){
		for(int j=0;j<10;j++){
			printf("%f ",dp[i][j][2]);
		}
		printf("\n");
	}*/
//	for(int i=0;i<10;i++) printf("%f ",getDis(0,i));
//	printf("\n");
	double ans=dp[N-3][N-2][N-1];
/*	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){
			if(ok[i][j]) printf("%f ",getDis(i,j));
			else printf("-1 ");
		}
		printf("\n");
	}*/
	if(ans<inf/2) printf("%.9f\n",ans-(3-K));
	else printf("-1\n");
	return 0;
}
accuracy: 0.25
time_ms: 1380
memory_kb: 36440
final_rank: 15

code_snippet: #include<cstdio>
#include<queue>
#include<utility>
#include<cmath>
#include<algorithm>

using namespace std;

typedef pair<int,int> P;
typedef pair<P,int> PP;
typedef pair<double,PP> State;

const double inf=1e9;
const double eps=1e-6;
const double eps2=1e-9;

P ps[110];
int N;
bool ok[110][110];//when y coordinate differ

int ss[3],ts[3];
double R;

double getDis(int i,int j){
	if(i==ts[0]&&j==N-3) return 0;
	if(i==ts[1]&&j==N-2) return 0;
	if(i==ts[2]&&j==N-1) return 0;
	int dx=ps[i].first-ps[j].first;
	int dy=ps[i].second-ps[j].second;
	return sqrt(dx*dx+dy*dy);
}

priority_queue<State,vector<State>,greater<State> > que;
double dp[110][110][110];

//State::State(double a,int i,int j,int k):first(a),second.first.first(i),second.first.second(j),second.second(k){}

State getState(double a,int i,int j,int k){
	State res;
	res.first=a;
	res.second.first.first=i;
	res.second.first.second=j;
	res.second.second=k;
	return res;
}

int lb[110],ub[110];
bool flg[110][110][110];

void trans2(State st){
//	printf("trans2\n");
	double cur=st.first;
	int i=st.second.first.first;
	int j=st.second.first.second;
	int k=st.second.second;
	if(dp[i][j][k]<cur) return;
	P tmp[]={P(i,0),P(j,1),P(k,2)};
	sort(tmp,tmp+3);
	if(ps[tmp[0].first]!=ps[tmp[2].first]){
		int l=lb[tmp[0].first];
		int r=ub[tmp[0].first];
		for(int x=l;x<=min(r,tmp[1].first-1);x++){
			for(int y=max(x+1,tmp[0].first+1);y<=r;y++){
				double add_dis=getDis(tmp[0].first,x)+getDis(tmp[1].first,y);
				double nxt=cur+add_dis;
				int ids[]={-1,-1,-1};
				ids[tmp[0].second]=x;
				ids[tmp[1].second]=y;
				ids[tmp[2].second]=tmp[2].first;
				if(dp[ids[0]][ids[1]][ids[2]]<nxt+eps2) continue;
				dp[ids[0]][ids[1]][ids[2]]=nxt;
				flg[ids[0]][ids[1]][ids[2]]=true;
				que.push(getState(nxt,ids[0],ids[1],ids[2]));
			}
		}
	}else{
		int l=lb[tmp[0].first];
		int r=ub[tmp[0].first];
		for(int x=l;x<=min(r,tmp[1].first-1);x++){
			for(int y=max(l,tmp[0].first+1);y<=min(r,tmp[2].first-1);y++){
				for(int z=max(l,tmp[1].first);z<=r;z++){
					double add_dis=getDis(tmp[0].first,x)+getDis(tmp[1].first,y)+getDis(tmp[2].first,z);
					double nxt=cur+add_dis;
					int ids[]={-1,-1,-1};
					ids[tmp[0].second]=x;
					ids[tmp[1].second]=y;
					ids[tmp[2].second]=z;
					if(dp[ids[0]][ids[1]][ids[2]]<nxt+eps2) continue;
					dp[ids[0]][ids[1]][ids[2]]=nxt;
					flg[ids[0]][ids[1]][ids[2]]=true;
					que.push(getState(nxt,ids[0],ids[1],ids[2]));
				}
			}
		}
	}
}


void trans(State st){
	double cur=st.first;
	int i=st.second.first.first;
	int j=st.second.first.second;
	int k=st.second.second;
//	printf("%f %d %d %d\n", cur,i,j,k);
	if(dp[i][j][k]<cur) return;
	int tmp[]={i,j,k};
	sort(tmp,tmp+3);
//	for(int i=0;i<3;i++) printf("%d ",tmp[i]);
//	printf("\n");
	if(ps[tmp[0]].second==ps[tmp[1]].second){
		//printf("a\n");
		if(flg[i][j][k]==false) trans2(st);
	}
	if(ps[i].second==ps[tmp[0]].second){
		for(int ni=i+1;ni<N;ni++){
			if(ok[i][ni]&&ps[i].second!=ps[ni].second){
				if(ni==j||ni==k) continue;
				double nxt=cur+getDis(i,ni);
				if(dp[ni][j][k]<nxt+eps2) continue;
				dp[ni][j][k]=nxt;
				que.push(getState(nxt,ni,j,k));
			}
		}
	}
	if(ps[j].second==ps[tmp[0]].second){
		for(int nj=j+1;nj<N;nj++){
			if(ok[j][nj]&&ps[j].second!=ps[nj].second){
				if(nj==i||nj==k) continue;
				double nxt=cur+getDis(j,nj);
				if(dp[i][nj][k]<nxt+eps2) continue;
				dp[i][nj][k]=nxt;
				que.push(getState(nxt,i,nj,k));
			}
		}
	}
	if(ps[k].second==ps[tmp[0]].second){
		for(int nk=k+1;nk<N;nk++){
			if(ok[k][nk]&&ps[k].second!=ps[nk].second){
				if(nk==i||nk==j) continue;
				double nxt=cur+getDis(k,nk);
				if(dp[i][j][nk]<nxt+eps2) continue;
				dp[i][j][nk]=nxt;
				que.push(getState(nxt,i,j,nk));
			}
		}
	}
}

void dijkstra(){
	for(int i=0;i<N;i++) for(int j=0;j<N;j++) for(int k=0;k<N;k++) dp[i][j][k]=inf;
	dp[ss[0]][ss[1]][ss[2]]=0;
	que.push(getState(0,ss[0],ss[1],ss[2]));
	while(!que.empty()){
		State st=que.top();
		que.pop();
		trans(st);
	}
}

bool check_can_go(int i,int j){
	int dx=ps[i].first-ps[j].first;
	int dy=ps[i].second-ps[j].second;
	if(dx*dx+dy*dy>R*R+eps) return false;
	for(int k=0;k<N;k++){
		int dx1=ps[i].first-ps[k].first;
		int dy1=ps[i].second-ps[k].second;
		int dx2=ps[j].second-ps[k].second;
		int dy2=ps[j].second-ps[k].second;
		if(dx1*dy2==dx2*dy1&&dx1*dx2+dy1*dy2<0) return false;
	}
}

int xs[110],ys[110];
PP rock_ids[110];
int s_[3],t_[3];
int K;

void precalc(){
	for(int i=K;i<=2;i++){
		xs[N]=i;
		ys[N]=10100;
		N++;
		xs[N]=i;
		ys[N]=10101;
		N++;
		s_[i]=N-2;
		t_[i]=N-1;
	}
	for(int i=0;i<3;i++){
		xs[N+i]=i;
		ys[N+i]=12000;
	}
	N+=3;
	for(int i=0;i<N;i++){
		rock_ids[i]=PP(P(ys[i],xs[i]),i);
	}
	sort(rock_ids,rock_ids+N);
	for(int i=0;i<N;i++){
		ps[i]=rock_ids[i].first;
		swap(ps[i].first,ps[i].second);
		for(int k=0;k<3;k++){
			int id=rock_ids[i].second;
			if(id==s_[k]) ss[k]=i;
			if(id==t_[k]) ts[k]=i;
		}
	}
	lb[0]=0;
	for(int i=1;i<N;i++){
		if(ps[i].second==ps[i-1].second) lb[i]=lb[i-1];
		else lb[i]=i;
	}
	ub[N-1]=N-1;
	for(int i=N-2;i>=0;i--){
		if(ps[i].second==ps[i+1].second) ub[i]=ub[i+1];
		else ub[i]=i;
	}
	for(int i=0;i<N;i++) for(int j=0;j<N;j++){
		ok[i][j]=check_can_go(i,j);
	}
	ok[ts[0]][N-3]=true;
	ok[ts[1]][N-2]=true;
	ok[ts[2]][N-1]=true;
/*	for(int i=0;i<N;i++){
		printf("%d %d\n",ps[i].first,ps[i].second);
	}
	for(int i=0;i<3;i++){
		printf("%d %d\n",ss[i],ts[i]);
	}*/
}

int main(){
	scanf("%d%d",&N,&K);
	scanf("%lf",&R);
	for(int i=0;i<K;i++){
		scanf("%d",s_+i);
		s_[i]--;
	}
	for(int i=0;i<K;i++){
		scanf("%d",t_+i);
		t_[i]--;
	}
	for(int i=0;i<N;i++){
		scanf("%d%d",xs+i,ys+i);
	}
	precalc();
//	for(int i=0;i<10;i++) printf("%d %d\n",ps[i].first,ps[i].second);
	dijkstra();
//	double ans=dp[ts[0]][ts[1]][ts[2]];
/*	for(int i=0;i<10;i++){
		for(int j=0;j<10;j++){
			printf("%f ",dp[i][j][2]);
		}
		printf("\n");
	}*/
//	for(int i=0;i<10;i++) printf("%f ",getDis(0,i));
//	printf("\n");
	double ans=dp[N-3][N-2][N-1];
/*	for(int i=0;i<N;i++){
		for(int j=0;j<N;j++){
			if(ok[i][j]) printf("%f ",getDis(i,j));
			else printf("-1 ");
		}
		printf("\n");
	}*/
	if(ans<inf/2) printf("%.9f\n",ans);
	else printf("-1\n");
	return 0;
}
accuracy: 0.07142857142857142
time_ms: 1370
memory_kb: 35852
final_rank: 19

code_snippet: #include<cstdio>
#include<queue>
#include<utility>
#include<cmath>
#include<algorithm>

using namespace std;

typedef pair<int,int> P;
typedef pair<P,int> PP;
typedef pair<double,PP> State;

const double inf=1e9;
const double eps=1e-6;
const double eps2=1e-9;

P ps[110];
int N;
bool ok[110][110];//when y coordinate differ

int ss[3],ts[3];
double R;

double getDis(int i,int j){
	int dx=ps[i].first-ps[j].first;
	int dy=ps[i].second-ps[j].second;
	return sqrt(dx*dx+dy*dy);
}

priority_queue<State,vector<State>,greater<State> > que;
double dp[110][110][110];

//State::State(double a,int i,int j,int k):first(a),second.first.first(i),second.first.second(j),second.second(k){}

State getState(double a,int i,int j,int k){
	State res;
	res.first=a;
	res.second.first.first=i;
	res.second.first.second=j;
	res.second.second=k;
	return res;
}

int lb[110],ub[110];
bool flg[110][110][110];

void trans2(State st){
//	printf("trans2\n");
	double cur=st.first;
	int i=st.second.first.first;
	int j=st.second.first.second;
	int k=st.second.second;
	if(dp[i][j][k]<cur) return;
	P tmp[]={P(i,0),P(j,1),P(k,2)};
	sort(tmp,tmp+3);
	if(ps[tmp[0].first]!=ps[tmp[2].first]){
		int l=lb[tmp[0].first];
		int r=ub[tmp[0].first];
		for(int x=l;x<=min(r,tmp[1].first-1);x++){
			for(int y=max(x+1,tmp[0].first+1);y<=r;y++){
				double add_dis=getDis(tmp[0].first,x)+getDis(tmp[1].first,y);
				double nxt=cur+add_dis;
				int ids[]={-1,-1,-1};
				ids[tmp[0].second]=x;
				ids[tmp[1].second]=y;
				ids[tmp[2].second]=tmp[2].first;
				if(dp[ids[0]][ids[1]][ids[2]]<nxt+eps2) continue;
				dp[ids[0]][ids[1]][ids[2]]=nxt;
				flg[ids[0]][ids[1]][ids[2]]=true;
				que.push(getState(nxt,ids[0],ids[1],ids[2]));
			}
		}
	}else{
		int l=lb[tmp[0].first];
		int r=ub[tmp[0].first];
		for(int x=l;x<=min(r,tmp[1].first-1);x++){
			for(int y=max(l,tmp[0].first+1);y<=min(r,tmp[2].first-1);y++){
				for(int z=max(l,tmp[1].first);z<=r;z++){
					double add_dis=getDis(tmp[0].first,x)+getDis(tmp[1].first,y)+getDis(tmp[2].first,z);
					double nxt=cur+add_dis;
					int ids[]={-1,-1,-1};
					ids[tmp[0].second]=x;
					ids[tmp[1].second]=y;
					ids[tmp[2].second]=z;
					if(dp[ids[0]][ids[1]][ids[2]]<nxt+eps2) continue;
					dp[ids[0]][ids[1]][ids[2]]=nxt;
					flg[ids[0]][ids[1]][ids[2]]=true;
					que.push(getState(nxt,ids[0],ids[1],ids[2]));
				}
			}
		}
	}
}


void trans(State st){
	double cur=st.first;
	int i=st.second.first.first;
	int j=st.second.first.second;
	int k=st.second.second;
//	printf("%f %d %d %d\n", cur,i,j,k);
	if(dp[i][j][k]<cur) return;
	int tmp[]={i,j,k};
	sort(tmp,tmp+3);
//	for(int i=0;i<3;i++) printf("%d ",tmp[i]);
//	printf("\n");
	if(ps[tmp[0]].second==ps[tmp[1]].second){
		//printf("a\n");
		if(flg[i][j][k]==false) trans2(st);
	}
	if(ps[i].second==ps[tmp[0]].second){
		for(int ni=i+1;ni<N;ni++){
			if(ok[i][ni]&&ps[i].second!=ps[ni].second){
				if(ni==j||ni==k) continue;
				double nxt=cur+getDis(i,ni);
				if(dp[ni][j][k]<nxt+eps2) continue;
				dp[ni][j][k]=nxt;
				que.push(getState(nxt,ni,j,k));
			}
		}
	}
	if(ps[j].second==ps[tmp[0]].second){
		for(int nj=j+1;nj<N;nj++){
			if(ok[j][nj]&&ps[j].second!=ps[nj].second){
				if(nj==i||nj==k) continue;
				double nxt=cur+getDis(j,nj);
				if(dp[i][nj][k]<nxt+eps2) continue;
				dp[i][nj][k]=nxt;
				que.push(getState(nxt,i,nj,k));
			}
		}
	}
	if(ps[k].second==ps[tmp[0]].second){
		for(int nk=k+1;nk<N;nk++){
			if(ok[k][nk]&&ps[k].second!=ps[nk].second){
				if(nk==i||nk==j) continue;
				double nxt=cur+getDis(k,nk);
				if(dp[i][j][nk]<nxt+eps2) continue;
				dp[i][j][nk]=nxt;
				que.push(getState(nxt,i,j,nk));
			}
		}
	}
}

void dijkstra(){
	for(int i=0;i<N;i++) for(int j=0;j<N;j++) for(int k=0;k<N;k++) dp[i][j][k]=inf;
	dp[ss[0]][ss[1]][ss[2]]=0;
	que.push(getState(0,ss[0],ss[1],ss[2]));
	while(!que.empty()){
		State st=que.top();
		que.pop();
		trans(st);
	}
}

bool check_can_go(int i,int j){
	int dx=ps[i].first-ps[j].first;
	int dy=ps[i].second-ps[j].second;
	if(dx*dx+dy*dy>R*R+eps) return false;
	for(int k=0;k<N;k++){
		int dx1=ps[i].first-ps[k].first;
		int dy1=ps[i].second-ps[k].second;
		int dx2=ps[j].second-ps[k].second;
		int dy2=ps[j].second-ps[k].second;
		if(dx1*dy2==dx2*dy1&&dx1*dx2+dy1*dy2<0) return false;
	}
}

int xs[110],ys[110];
PP rock_ids[110];
int s_[3],t_[3];
int K;

void precalc(){
	for(int i=K;i<=2;i++){
		xs[N]=i;
		ys[N]=10100;
		N++;
		xs[N]=i;
		ys[N]=10101;
		N++;
		s_[i]=N-2;
		t_[i]=N-1;
	}
		for(int i=0;i<N;i++){
		rock_ids[i]=PP(P(ys[i],xs[i]),i);
	}
	sort(rock_ids,rock_ids+N);
	for(int i=0;i<N;i++){
		ps[i]=rock_ids[i].first;
		swap(ps[i].first,ps[i].second);
		for(int k=0;k<3;k++){
			int id=rock_ids[i].second;
			if(id==s_[k]) ss[k]=i;
			if(id==t_[k]) ts[k]=i;
		}
	}
	lb[0]=0;
	for(int i=1;i<N;i++){
		if(ps[i].second==ps[i-1].second) lb[i]=lb[i-1];
		else lb[i]=i;
	}
	ub[N-1]=N-1;
	for(int i=N-2;i>=0;i--){
		if(ps[i].second==ps[i+1].second) ub[i]=ub[i+1];
		else ub[i]=i;
	}
	for(int i=0;i<N;i++) for(int j=0;j<N;j++){
		ok[i][j]=check_can_go(i,j);
	}/*
	for(int i=0;i<N;i++){
		printf("%d %d\n",ps[i].first,ps[i].second);
	}
	for(int i=0;i<3;i++){
		printf("%d %d\n",ss[i],ts[i]);
	}*/
}

int main(){
	scanf("%d%d",&N,&K);
	scanf("%lf",&R);
	for(int i=0;i<K;i++){
		scanf("%d",s_+i);
		s_[i]--;
	}
	for(int i=0;i<K;i++){
		scanf("%d",t_+i);
		t_[i]--;
	}
	for(int i=0;i<N;i++){
		scanf("%d%d",xs+i,ys+i);
	}
	precalc();
//	for(int i=0;i<10;i++) printf("%d %d\n",ps[i].first,ps[i].second);
	dijkstra();
	double ans=dp[ts[0]][ts[1]][ts[2]];
/*	for(int i=0;i<10;i++){
		for(int j=0;j<10;j++){
			printf("%f ",dp[i][j][2]);
		}
		printf("\n");
	}*/
//	for(int i=0;i<10;i++) printf("%f ",getDis(0,i));
//	printf("\n");
	if(ans<inf/2) printf("%.9f\n",ans);
	else printf("-1\n");
	return 0;
}
accuracy: 0.07142857142857142
time_ms: 1330
memory_kb: 36308
final_rank: 18

code_snippet: #include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <set>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

#include <complex>
typedef complex<double> Point;
static const double INF = 1e+10;

struct Line : public vector<Point> {
  Line() {;}
  Line(Point a, Point b) { push_back(a); push_back(b); }
};

namespace std {
  bool operator<(const Point &lhs, const Point &rhs) {
    return lhs.imag() == rhs.imag() ? lhs.real() < rhs.real() : lhs.imag() < rhs.imag();
  }
}

bool intersectSP(const Line &s, const Point &p) {
  return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS;
}

inline bool chmin(double &lhs, const double &rhs) {
  if (lhs - rhs < EPS) { return false; }
  lhs = rhs;
  return true;
}

enum {
  UP = 1,
  RIGHT = 2,
  LEFT = 4
};
typedef double Weight;
struct Edge {
  int type;
  int src;
  int dest;
  Weight weight;
  Edge(int type, int src, int dest, Weight weight) : type(type), src(src), dest(dest), weight(weight) {;}
};
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;
typedef vector<Weight> Array;
typedef vector<Array> Matrix;

double dp[4][101][101][101];
int n, k;
double r;
Point ps[110];
int end[3];

struct State {
  int state;
  int pos[3];
  double cost;
  double a;
  void CalcA() {
    a = 0;
    REP(i, k) {
      a += abs(ps[pos[i]] - ps[end[i]]);
    }
  }
  bool operator<(const State &rhs) const {
    return cost + a > rhs.cost + rhs.a;
  }
};


vector<pair<Point, int> > CalcBackest(const State &s) {
  vector<pair<Point, int> > ret;
  REP(i, k) {
    if (s.pos[i] == end[i]) { continue; }
    ret.push_back(make_pair(ps[s.pos[i]], i));
  }
  sort(ret.begin(), ret.end());
  while (ret.size() > 1 && ret.front().first.imag() != ret.back().first.imag()) { ret.pop_back(); }
  return ret;
}

int CalcIndex(const State &s) {
  vector<pair<Point, int> > indexs = CalcBackest(s);
  int rest = indexs.size();
  if (rest == 0) { return -1; }
  if (s.state == 3) {
    return indexs.back().second + 6 + rest * 10;
  }

  if (rest == 1) { return indexs[0].second + rest * 10; }
  if (s.state == 0) { return indexs[0].second + 3 + rest * 10; }
  if (s.state == 1) { return indexs[1].second + 3 + rest * 10; }
  if (s.state == 2) {
    assert(rest == 3);
    return indexs[2].second + 3 + rest * 10;
  }
  assert(false);
  return -1;
}

int CalcState(const Edge &e, const State &s, int next, int prest) {
  REP(i, k) REP(j, i) {
    if (s.pos[i] == s.pos[j]) { return -1; }
  }
  REP(i, k) {
    if (ps[s.pos[i]].imag() > ps[end[i]].imag()) { return -1; }
  }
  int rest = CalcBackest(s).size();
  if (s.state == 3 && prest == 1 && e.type == UP) { return 0; }
  if (s.state == 0 && prest == 1) { return 0; }
  if (s.state < 3 && s.state >= rest) { return 3; }
  if (s.state < 3 && !next) { return s.state; }
  if (s.state < 3) {
    if (s.state + 1 >= rest) { return 3; }
    return s.state + 1;
  }
  return 3;
}

int main() {
  while (scanf("%d %d %lf", &n, &k, &r) > 0) {
    State ini;
    ini.state = 0;
    ini.cost = 0;
    ini.pos[0] = ini.pos[1] = ini.pos[2] = n;
    end[0] = end[1] = end[2] = n;
    REP(i, k) {
      int p;
      scanf("%d", &p);
      ini.pos[i] = p - 1;
    }
    REP(i, k) {
      scanf("%d", &end[i]);
      end[i]--;
    }
    REP(i, n) {
      double x, y;
      scanf("%lf %lf", &x, &y);
      ps[i] = Point(x, y);
    }
    ps[n] = Point(1e+8, 1e+8);
    Graph g(n + 1);
    REP(i, n) {
      g[i].push_back(Edge(UP | LEFT | RIGHT, i, i, 0));
    }
    REP(i, n) REP(j, n) {
      if (i == j) { continue; }
      if (norm(ps[i] - ps[j]) - r * r < EPS && ps[i].imag() <= ps[j].imag()) {
        REP(k, n) {
          if (i == k || j == k) { continue; }
          if (intersectSP(Line(ps[i], ps[j]), ps[k])) { goto next; }
        }
        double d = abs(ps[i] - ps[j]);
        int type = UP;
        if (ps[i].imag() == ps[j].imag()) {
          type = ps[i].real() <= ps[j].real() ? RIGHT : LEFT;
        }
        //cout << i << " " << j << " " << type << endl;
        g[i].push_back(Edge(type, i, j, d));
      }
next:;
    }
    ini.CalcA();
    REP(i, 4) REP(j, 101) REP(k, 101) REP(l, 101) { dp[i][j][k][l] = 1e+100; }
    dp[0][ini.pos[0]][ini.pos[1]][ini.pos[2]] = ini.a;
    priority_queue<State> que;
    que.push(ini);
    while (!que.empty()) {
      State s = que.top();
      que.pop();
      if (s.pos[0] == end[0] && s.pos[1] == end[1] && s.pos[2] == end[2]) { break; }
      int index = CalcIndex(s);
      if (index < 0) { continue; }
      if (dp[s.state][s.pos[0]][s.pos[1]][s.pos[2]] - s.cost - s.a > EPS) { continue; }
      int rest = index / 10;
      assert(rest > 0);
      index %= 10;
      int okType = UP | LEFT | RIGHT;
      if (3 <= index && index <= 6) { okType = RIGHT; }
      if (6 <= index && index < 9) { okType = UP | LEFT; }
      index %= 3;
      //cout << s.state << " " << s.pos[0] << " " << s.pos[1] << " " << (int)s.pos[2] << " " << okType << endl;
      FORIT(it, g[s.pos[index]]) {
        if (!(it->type & okType)) { continue; }
        REP(e, 2) {
          State ns = s;
          ns.cost = s.cost + it->weight;
          ns.pos[index] = it->dest;
          ns.state = CalcState(*it, ns, e, rest);
          ns.CalcA();
          //cout << it->src << " " << it->dest << endl;
          if (ns.state < 0) { continue; }
          if (!chmin(dp[ns.state][ns.pos[0]][ns.pos[1]][ns.pos[2]], ns.cost + ns.a)) { continue; }
          que.push(ns);
        }
      }
    }
    double ans = 1e+100;
    REP(i, 4) { ans = min(ans, dp[i][end[0]][end[1]][end[2]]); }
    if (ans < 1e+100) {
      printf("%.8f\n", ans);
    } else {
      puts("-1");
    }
  }
}
accuracy: 1
time_ms: 560
memory_kb: 0
final_rank: 3