Problem:
E: ジャム (Jam)

問題

ある国には N 個の街があり、1,\ 2,\ ...,\ N の番号がつけられています。これらの街は M 本の道で双方向に結ばれており、i 番目の道を使うと街 u_i と v_i の間を時間 t_i で移動することができます。また、どの 2 つの街もいくつかの道を使うことで行き来することができます。

それぞれの街では食パンが売られており、街 i で売られている食パンの美味しさは P_i です。

さらに、この国には K 種類の味のジャムがあり、街 i では味 c_i で美味しさ J_i のジャムを買うことができます。

街 1 に住んでいるほむちゃんは、これからパンとジャムを 1 つずつ買いにお出かけすることにしました。ほむちゃんは、いくつかの街を移動してパンとジャムを買って街 1 に戻ってきます。より正確には、ある街 u に移動してパンを買い、ある街 v を選んでジャムを買い、街 1 に戻ってきます。この際、u=v や u=1 、v=1 でも構いません。

お買い物を終えたほむちゃんの幸福度は、「買ったパンとジャムの美味しさの合計」ー「移動にかかった時間」です。K 種類それぞれのジャムについて、その味のジャムとパンを買いに行くときの幸福度として考えられる最大値を計算してください。

入力形式

N M K
P_1 P_2 ... P_N
c_1 c_2 ... c_N
J_1 J_2 ... J_N
u_1 v_1 t_1
u_2 v_2 t_2
:
u_M v_M t_M

制約

1\leq N\leq 10^5

1\leq M\leq 2\times 10^5

1\leq K\leq N

1\leq P_i, J_i\leq 10^9

1\leq c_i\leq K

1\leq u_i, v_i \leq N

1\leq t_i \leq 10^9

すべての i\ (1\leq i\leq K) について、c_j=i となるj\ (1\leq j\leq N) が存在する

与えられるグラフは多重辺や自己ループを含まない連結なグラフである

入力はすべて整数で与えられる

出力形式

K 行出力してください。i 行目にはパンと味 i のジャムを買いに行く場合の幸福度の最大値を出力してください。

入力例 1

4 4 3
3 6 1 6
1 1 2 3
6 1 5 5
1 2 1
2 3 1
1 3 1
1 4 1

出力例 1

10
8
9

味 1 のジャムを買う場合

街 1 でジャムを買い、街 2 に移動してパンを買い、街 1 に戻ってくると、幸福度は 6+6-2=10 となりこれが最適です。

味 2 のジャムを買う場合

街 2 に移動してパンを買い、街 3 に移動してジャムを買い、街 1 に戻ってくると、幸福度は 6+5-3=8 となります。

味 3 のジャムを買う場合

街 4 に移動してパンとジャムの両方を買って街 1 に戻ってくると、幸福度は 6+5-2=9 となります。

入力例 2

2 1 2
1 1
1 2
1 1
1 2 1000000000

出力例 2

2
-1999999998

パンやジャムの美味しさに比べて距離が遠すぎるのでほむちゃんは不満そうです。

入力例 3

6 8 3
31 41 59 26 53 58
1 2 3 1 2 3
27 18 28 18 28 46
1 2 3
2 3 7
2 4 8
3 6 9
3 5 3
4 5 3
1 5 15
4 6 7

出力例 3

66
61
68

Solution in C (judge verdict: Accepted)

#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<inttypes.h>

typedef int32_t i32;
typedef int64_t i64;

typedef struct binary_heap {
  void *array;
  size_t heap_size;
  size_t max_size;
  size_t val_size;
  int (*cmp) (const void *, const void *);
} heap;

heap* new_binary_heap (const size_t val_size, int (*cmp_func) (const void *, const void *)) {
  heap *h = (heap *) calloc (1, sizeof (heap));
  h->array = malloc (val_size * (1 + 1));
  h->heap_size = 0;
  h->max_size = 1;
  h->val_size = val_size;
  h->cmp = cmp_func;
  return h;
}

int is_empty (const heap *h) {
  return h->heap_size == 0;
}

static inline void heap_func_swap (void * restrict a, void * restrict b, size_t val_size) {
  if ((val_size & 7) == 0) {
    uint64_t *p = (uint64_t *) a;
    uint64_t *q = (uint64_t *) b;
    val_size /= sizeof (uint64_t);
    while (val_size--) {
      const uint64_t tmp = *p;
      *p++ = *q;
      *q++ = tmp;
    }
  } else {
    uint8_t *p = (uint8_t *) a;
    uint8_t *q = (uint8_t *) b;
    while (val_size--) {
      const uint8_t tmp = *p;
      *p++ = *q;
      *q++ = tmp;
    }
  }
}

static inline void heap_func_copy (void * restrict dst, const void * restrict src, size_t val_size) {
  if ((val_size & 7) == 0) {
    const uint64_t *p = (const uint64_t *) src;
    uint64_t *q = (uint64_t *) dst;
    val_size /= sizeof (uint64_t);
    while (val_size--) {
      *q++ = *p++;
    }
  } else {
    const uint8_t *p = (const uint8_t *) src;
    uint8_t *q = (uint8_t *) dst;
    while (val_size--) {
      *q++ = *p++;
    }
  }
}

void push (heap * const h, const void *val) {
  if (h->heap_size == h->max_size) {
    h->max_size = 2 * h->max_size + 1;
    h->array = realloc (h->array, h->val_size * (h->max_size + 1));
  }
  h->heap_size++;
  uint8_t * const array = (uint8_t *) h->array;
  size_t k = h->heap_size;
  const size_t val_size = h->val_size;
  int (* const cmp) (const void *, const void *) = h->cmp;
  heap_func_copy(array + k * val_size, val, val_size);
  while (k > 1) {
    size_t parent = k / 2;
    if (cmp (array + parent * val_size, array + k * val_size) <= 0) {
      return;
    }
    heap_func_swap (array + parent * val_size, array + k * val_size, val_size);
    k = parent;
  }
}

void pop (heap * const h, void *res) {
  uint8_t * const array = (uint8_t *) h->array;
  const size_t val_size = h->val_size;
  if (res != NULL) {
    heap_func_copy (res, array + val_size, val_size);
  }
  heap_func_copy (array + val_size, array + val_size * h->heap_size, val_size);
  h->heap_size--;
  int (* const cmp) (const void *, const void *) = h->cmp;
  const size_t n = h->heap_size;
  size_t k = 1;
  while (2 * k  + 1 <= n) {
    const int c = cmp (array + val_size * 2 * k, array + val_size * (2 * k + 1));
    const size_t next = 2 * k + (c <= 0 ? 0 : 1);
    if (cmp (array + val_size * k, array + val_size * next) <= 0) return;
    heap_func_swap (array + val_size * k, array + val_size * next, val_size);
    k = next;
  }
  if (2 * k <= n && cmp (array + val_size * k, array + val_size * 2 * k) > 0) {
    heap_func_swap (array + val_size * k, array + val_size * 2 * k, val_size);
  }
}

typedef int32_t edge_weight;

typedef struct directed_edge {
  int32_t vertex;
  int32_t next;
  edge_weight cost;
} graph_edge;

typedef struct directedGraph {
  graph_edge *edge;
  int32_t *start;
  int32_t pointer;
  int32_t vertex_num;
  int32_t edge_max_size;
} graph;

graph* new_graph (const int vertex_num) {
  graph *g = (graph *) calloc (1, sizeof (graph));
  g->edge = (graph_edge *) calloc (1, sizeof (graph_edge));
  g->start = (int32_t *) calloc (vertex_num, sizeof (int32_t));
  g->pointer = 0;
  g->vertex_num = vertex_num;
  g->edge_max_size = 1;
  for (int32_t i = 0; i < vertex_num; ++i) {
    g->start[i] = -1;
  }
  return g;
}

void add_edge (graph *g, int32_t from, int32_t to, edge_weight cost) {
  if (g->pointer == g->edge_max_size) {
    g->edge_max_size *= 2;
    g->edge = (graph_edge *) realloc (g->edge, sizeof (graph_edge) * g->edge_max_size);
  }
  g->edge[g->pointer] = (graph_edge) {to, g->start[from], cost};
  g->start[from] = g->pointer++;
}

#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
#define ALLOC(size,type) ((type*)calloc((size),sizeof(type)))

typedef struct node {
  i32 v;
  i64 d;
} node;

int cmp_node (const void *a, const void *b) {
  i64 d = ((node *)a)->d - ((node *)b)->d;
  return d == 0 ? 0 : d < 0 ? -1 : 1;
}

void run (void) {
  i32 n, m, k;
  scanf ("%" SCNi32 "%" SCNi32 "%" SCNi32, &n, &m, &k);
  i32 *p = ALLOC (3 * n, i32);
  i32 *c = p + n;
  i32 *t = c + n;
  for (i32 i = 0; i < 3 * n; ++i) {
    scanf ("%" SCNi32, p + i);
  }
  const i32 sup = 1000000000 + 1;
  graph *g = new_graph (2 * n);
  for (i32 i = 0; i < n; ++i) {
    add_edge (g, i, i + n, sup - p[i]);
  }
  while (m--) {
    i32 a, b, d;
    scanf ("%" SCNi32 "%" SCNi32 "%" SCNi32, &a, &b, &d);
    a--; b--;
    add_edge (g, a, b, d);
    add_edge (g, b, a, d);
    a += n; b += n;
    add_edge (g, a, b, d);
    add_edge (g, b, a, d);
  }
  i64 *dp = ALLOC (2 * n, i64);
  for (i32 i = 1; i < 2 * n; ++i) {
    dp[i] = (i64) 1000000001 * 2 * n;
  }
  heap *h = new_binary_heap (sizeof (node), cmp_node);
  push (h, &(node){0, 0});
  while (!is_empty (h)) {
    node t;
    pop (h, &t);
    if (t.d > dp[t.v]) continue;
    for (i32 p = g->start[t.v]; p != -1; p = g->edge[p].next) {
      i32 u = g->edge[p].vertex;
      i64 d = t.d + g->edge[p].cost;
      if (d >= dp[u]) continue;
      dp[u] = d;
      push (h, &(node){u, d});
    }
  }
  i64 *max = ALLOC (k + 1, i64);
  for (i32 i = 1; i <= k; ++i) {
    max[i] = 2 - (i64)1000000001 * 2 * n;
  }
  for (i32 i = 0; i < n; ++i) {
    i64 v = (sup - dp[i + n]) - dp[i] + t[i];
    max[c[i]] = MAX (max[c[i]], v);
  }
  for (i32 i = 1; i <= k; ++i) {
    printf ("%" PRIi64 "\n", max[i]);
  }
}

int main (void) {
  run();
  return 0;
}