Official

B - 救急ヘリコプターの配置 / Placement of Emergency Helicopters Editorial by physics0523


当然ながら、クエリで尋ねられるのは \(1,2,\dots,N\)\(N\) 通りです。
なので、全ての集落に対して以下の流れで解を予め計算しておくことを考えます。

  • \(i=1,2,\dots,N\) について、以下を繰り返す。
    • \(j=i+1,i+2,\dots,N\) について、以下を繰り返す。
      • \(i,j\) 間のコスト増分を、 \(i,j\) それぞれの解に加算する。

後は、 \(\lfloor \sqrt{x} \rfloor\) が求められればよいです。
色々と方法がありますが、 C++ にて \(x\)long long の範囲に収まる場合は sqrt を利用して値を近似した後で調整する実装例のような方法が簡単でしょう。

本解法の計算量は \(O(N^2+Q)\) です。

実装例 (C++):

#include<bits/stdc++.h>

using namespace std;
using ll=long long;

ll sqrt_floor(ll x){
  ll v=sqrt((long double)x);
  while(v*v<x){v++;}
  while(v*v>x){v--;}
  return v;
}

int main(){
  ll N,Q;
  cin >> N >> Q;
  vector<ll> X(N),Y(N);
  for(ll i=0;i<N;i++){
    cin >> X[i] >> Y[i];
  }
  vector<ll> ans(N,0);
  for(ll i=0;i<N;i++){
    for(ll j=i+1;j<N;j++){
      ll del=(X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]);
      del=sqrt_floor(del);
      ans[i]+=del;
      ans[j]+=del;
    }
  }
  while(Q--){
    ll C;
    cin >> C;
    cout << ans[C-1] << "\n";
  }
  return 0;
}

posted:
last update: