ferinの競プロ帳

競プロについてのメモ

AOJ0616 JOI公園

問題ページ
JOI 公園 | Aizu Online Judge

考えたこと

とりあえず広場1から各広場への最短距離はdijkstraで求まる。Xを決めれば各辺について両端の頂点への最短距離がX以下かどうかでその辺が撤去される辺か判断できるのでO(M)でできる。max(X) = 10^10 でまず間に合わない。Xとして取りうる値は各頂点で最短距離となる値しかありえず、O(N)で抑えられる。しかしこれでもO(NM)で不可能。
各辺について両端の頂点の最短距離の大きい方をXに選択するときその辺を撤去する。したがって各Xの撤去すべき辺の合計をO(M)で前計算しておける。Xの候補のうち小さいものから考えていけば一度撤去した辺が撤去されないことはありえない。したがってO(N+M)で解ける。

//#define __USE_MINGW_ANSI_STDIO 0
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<ll> VL;
typedef vector<VL> VVL;
typedef pair<int, int> PII;

#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(x) x.begin(), x.end()
#define IN(a, b, x) (a<=x&&x<b)
#define MP make_pair
#define PB push_back
const int INF = (1LL<<30);
const ll LLINF = (1LL<<60);
const double PI = 3.14159265359;
const double EPS = 1e-12;
const int MOD = 1000000007;
#define int ll

template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); }

int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};

struct edge{ll to, cost;};

int n, d[100010];
vector<edge> g[100010];

void dijkstra(int s) {
  priority_queue<PII, vector<PII>, greater<PII>> que;
  fill(d, d+n, INF);
  d[s] = 0;
  que.push(PII{0, s});

  while(que.size()) {
    PII p = que.top(); que.pop();
    int v = p.second;
    if(d[v] < p.first) continue;
    for(edge e: g[v]) {
      if(d[e.to] > d[v] + e.cost) {
        d[e.to] = d[v] + e.cost;
        que.push(PII{d[e.to], e.to});
      }
    }
  }
}

int a[200010], b[200010], cost[200010];
map<ll, ll> mp;
signed main(void)
{
  int m, c;
  cin >> n >> m >> c;
  ll sum = 0;
  REP(i, m) {
    cin >> a[i] >> b[i] >> cost[i];
    a[i]--, b[i]--;
    g[a[i]].PB({b[i], cost[i]});
    g[b[i]].PB({a[i], cost[i]});
    sum += cost[i];
  }

  dijkstra(0);

  VL v;
  REP(i, n) v.PB(d[i]);
  sort(ALL(v));
  v.erase(unique(ALL(v)), v.end());

  //辺について見ていく
  REP(i, m) {
    ll tmp = max(d[a[i]], d[b[i]]);
    if(mp.find(tmp) == mp.end()) mp[tmp] = cost[i];
    else mp[tmp] += cost[i];
  }

  ll ret = LLINF;
  for(int i: v) {
    chmin(ret, c*i+(sum-mp[i]));
    sum -= mp[i];
  }
  cout << ret << endl;

  return 0;
}