結果

問題 No.1069 電柱 / Pole (Hard)
コンテスト
ユーザー Nachia
提出日時 2026-01-14 14:48:24
言語 C++17
(gcc 15.2.0 + boost 1.89.0)
結果
AC  
実行時間 11 ms / 2,000 ms
コード長 7,994 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 2,396 ms
コンパイル使用メモリ 156,476 KB
実行使用メモリ 7,848 KB
最終ジャッジ日時 2026-01-14 14:48:30
合計ジャッジ時間 5,757 ms
ジャッジサーバーID
(参考情報)
judge4 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 4
other AC * 79
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#define PROBLEM "https://yukicoder.me/problems/no/1069"
#define ERROR 0.0001
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
using ll = long long;
const ll INF = 1ll << 60;
#define REP(i,n) for(ll i=0; i<ll(n); i++)
template <class T> using V = vector<T>;
template <class A, class B> void chmax(A& l, const B& r){ if(l < r) l = r; }
template <class A, class B> void chmin(A& l, const B& r){ if(r < l) l = r; }


#include <vector>
#include <queue>
#include <utility>
#include <optional>

struct ShortestPathProblemUndirected {
  using Weight = double;
  struct Edge { int u, v, uv, id; Weight w; };
  int n;
  Weight inf;
  Weight zero;
  std::vector<Edge> edges;
  std::vector<std::vector<int>> inc;
  int s;
  int t;

  ShortestPathProblemUndirected(int _n, Weight _inf, Weight _zero, int _s, int _t)
    : n(_n), inf(_inf), zero(_zero), edges(), inc(_n), s(_s), t(_t) {}

  int addEdge(int u, int v, Weight w){
    int e = edges.size();
    edges.push_back({ u, v, u ^ v, e, w });
    inc[u].push_back(e);
    inc[v].push_back(e);
    return e;
  }

  struct ShortestPathTree {
    std::vector<int> parent;
    std::vector<Weight> dist;
    std::vector<int> root;
    void resize(int n, Weight inf){
      parent.resize(n, -1);
      dist.resize(n, inf);
      root.resize(n, -1);
    }
  };

  void updateTree(const std::vector<bool>& edgeMask, ShortestPathTree& tree){
    ShortestPathTree t; std::swap(t, tree);
    using Node = std::pair<Weight, int>;
    std::priority_queue<Node, std::vector<Node>, std::greater<Node>> que;
    auto check = [&](int v, int p, int r, Weight d) -> void {
      if(!(d < t.dist[v])) return;
      t.dist[v] = d;
      t.parent[v] = p;
      t.root[v] = r;
      que.push({ d, v });
    };
    for(int v=0; v<n; v++) if(t.root[v] != -1) que.push({t.dist[v], v});
    while(que.size()){
      auto [d, v] = que.top(); que.pop();
      if(t.dist[v] < d) continue;
      for(int e : inc[v]) if(edgeMask[e]){
        check(v ^ edges[e].uv, e, t.root[v], d + edges[e].w);
      }
    }
    std::swap(t, tree);
  }

  std::vector<int> getPath(const ShortestPathTree& t, int start){
    std::vector<int> path;
    for(int v=start; t.root[v]!=v; v^=edges[path.back()].uv){
      if(t.parent[v] < 0) return {};
      path.push_back(t.parent[v]);
    }
    std::reverse(path.begin(), path.end());
    return path;
  }

  ShortestPathTree solve(const std::vector<bool>& edgeMask){
    ShortestPathTree tree; tree.resize(n, inf);
    tree.root[s] = s;
    tree.dist[s] = zero;
    updateTree(edgeMask, tree);
    return tree;
  }

  struct Instance {
    ShortestPathProblemUndirected* data;
    std::vector<bool> edgeMask;
    Weight wt;
    std::vector<int> path;
    std::vector<std::pair<int, Weight>> cand;
    int lim;

    struct SplitResult {
      std::vector<int> path;
      std::vector<Instance> newInstances;
    };

    Instance(ShortestPathProblemUndirected* _data, std::vector<bool> _edgeMask)
      : data(_data), edgeMask(_edgeMask) {}

    bool solve(){
      auto tree = data->solve(edgeMask);
      path = data->getPath(tree, data->t);
      if(path.empty()) return false;
      lim = path.size();
      return true;
    }

    bool solve2nd(){
      ShortestPathTree treeS, treeT;
      treeS.resize(data->n, data->inf);
      treeT.resize(data->n, data->inf);
      int pathLen = path.size();
      std::vector<int> pathVtx(pathLen + 1);
      pathVtx[0] = data->s;
      for(int i=0; i<pathLen; i++) pathVtx[i+1] = pathVtx[i] ^ data->edges[path[i]].uv;

      for(int h : {data->s, data->t}){
        treeS.dist[h] = data->zero;
        treeS.root[h] = h;
        for(int i=0; i<pathLen; i++){
          auto e = data->edges[path[i]];
          treeS.root[pathVtx[i+1]] = pathVtx[i+1];
          treeS.dist[pathVtx[i+1]] = treeS.dist[pathVtx[i]] + e.w;
        }
        data->updateTree(edgeMask, treeS);
        std::swap(treeS, treeT);
        std::reverse(path.begin(), path.end());
        std::reverse(pathVtx.begin(), pathVtx.end());
      }
      std::vector<int> mainPath(data->edges.size(), -1);
      for(int i=0; i<pathLen; i++) mainPath[path[i]] = i;
      std::vector<int> mainPathVtx(data->n, -1);
      for(int i=0; i<=pathLen; i++) mainPathVtx[pathVtx[i]] = i;

      std::vector<Weight> nextWeight(pathLen, data->inf);
      for(int i=0; i<int(data->edges.size()); i++) if(edgeMask[i] && mainPath[i] == -1){
        auto e = data->edges[i];
        for(int t=0; t<2; t++){
          std::swap(e.u, e.v);
          if(treeS.root[e.u] < 0 || treeT.root[e.v] < 0) continue;
          if(mainPathVtx[treeS.root[e.u]] >= mainPathVtx[treeT.root[e.v]]) continue;
          Weight& dest = nextWeight[mainPathVtx[treeS.root[e.u]]];
          dest = std::min(dest, e.w + treeS.dist[e.u] + treeT.dist[e.v]);
        }
      }

      Weight minWeight = data->inf;
      for(int i=0; i<lim; i++) if(nextWeight[i] < minWeight){
        minWeight = nextWeight[i];
        cand.push_back({ i, minWeight });
      }
      wt = minWeight;
      return !cand.empty();
    }

    static SplitResult split(Instance src){
      SplitResult res;
      auto [rank, weight] = src.cand.back();
      src.cand.pop_back();

      {
        auto nextEdgeMask = src.edgeMask;
        int p = src.data->s;
        for(int i=0; i<rank; i++){
          for(int e : src.data->inc[p]) nextEdgeMask[e] = false;
          p ^= src.data->edges[src.path[i]].uv;
        }
        for(int i=0; i<rank; i++) nextEdgeMask[src.path[i]] = true;
        nextEdgeMask[src.path[rank]] = false;
        Instance buf(src.data, std::move(nextEdgeMask));
        buf.solve();
        res.path = buf.path;
        if(buf.solve2nd()) res.newInstances.push_back(std::move(buf));
      }

      {
        auto nextEdgeMask = src.edgeMask;
        int p = src.data->s;
        for(int i=0; i<=rank; i++){
          for(int e : src.data->inc[p]) nextEdgeMask[e] = false;
          p ^= src.data->edges[src.path[i]].uv;
        }
        for(int i=0; i<=rank; i++) nextEdgeMask[src.path[i]] = true;
        nextEdgeMask[src.path[rank]] = false;
        Instance buf(src.data, std::move(nextEdgeMask));
        buf.path = src.path;
        buf.lim = src.lim;
        if(buf.solve2nd()) res.newInstances.push_back(std::move(buf));
      }
      
      if(src.cand.size()){
        src.wt = src.cand.back().second;
        src.lim = rank;
        res.newInstances.push_back(std::move(src));
      }
      
      return res;
    }
  };

  struct CmpWt {
    bool operator()(const Instance& l, const Instance& r){
      return r.wt < l.wt;
    }
  };

  std::priority_queue<Instance, std::vector<Instance>, CmpWt> que;
  bool KthStarted = false;

  std::optional<std::vector<int>> getNextSmallest(){
    if(!KthStarted){
      KthStarted = true;
      Instance inst(this, std::vector<bool>(edges.size(), true));
      if(!inst.solve()) return std::nullopt;
      auto res = inst.path;
      if(inst.solve2nd()) que.push(std::move(inst));
      return res;
    }
    if(que.empty()) return std::nullopt;
    auto h = Instance::split(que.top()); que.pop();
    for(auto& nx : h.newInstances) que.push(std::move(nx));
    return h.path;
  }
};

#include <cmath>

void testcase(){
  std::cout.precision(15);
  std::cout << std::fixed;

  int N, M, K; cin >> N >> M >> K;
  int X, Y; cin >> X >> Y; X--; Y--;
  std::vector<int> posX(N), posY(N);
  for(int i=0; i<N; i++) std::cin >> posX[i] >> posY[i];

  ShortestPathProblemUndirected task(N, 1.0e100, 0, X, Y);
  for(int i=0; i<M; i++){
    int u,v; std::cin >> u >> v; u--; v--;
    task.addEdge(u, v, hypot(double(posX[u] - posX[v]), double(posY[u] - posY[v])) + 1.0e-8);
  }

  for(int k=0; k<K; k++){
    auto buf = task.getNextSmallest();
    if(buf.has_value()){
      double h = 0;
      for(auto e : *buf) h += task.edges[e].w;
      std::cout << h << "\n";
    } else {
      std::cout << "-1\n";
    }
  }
}

int main(){
  cin.tie(0)->sync_with_stdio(0);
  testcase();
  return 0;
}
0