Cod sursă (job #144267)

Utilizator avatar spatarel Spatarel Dan-Constantin spatarel IP ascuns
Problemă Termite (lot seniori) Compilator cpp | 3,02 kb
Rundă Status evaluat
Dată 27 apr. 2015 00:01:34 Scor ascuns
// Andrei Parvu

// Timpul este un cerc plat: ori de cate ori vom rula acest program, nodurile
// tot in acelasi moment de timp se vor desparti

#include <cstdio>
#include <cstring>

#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

const int NMAX = 300000;

// p-asta il faci 2 daca vrei sa fiecare termita sa plece la un anumit moment
// de timp (nu neaparat la 0)
#define TYPE 1

#define START 0

int father[NMAX + 1], edge_cost[NMAX + 1], h[NMAX + 1];
vector<pair<int, int> > v[NMAX + 1];

int cost[NMAX + 1];
vector<pair<int, int> > dists;

bool in_queue[NMAX + 1];
int part_cost[NMAX + 1], have_been[NMAX + 1];

int link_up(int x) {
  for (; father[x]; x = father[x]);

  return x;
}

void unite(int x, int y, int cost) {
  x = link_up(x);
  y = link_up(y);

  if (x == y) {
    return ;
  }

  if (h[x] < h[y]) {
    father[x] = y;
    edge_cost[x] = cost;
  } else {
    if (h[x] == h[y]) {
      h[x]++;
    }
    father[y] = x;
    edge_cost[y] = cost;
  }
}

int main() {
  freopen("termite.in", "rt", stdin);
  freopen("termite.out", "wt", stdout);

  int n, m, k, q;

  scanf("%d%d%d%d", &n, &m, &k, &q);
  for (int i = 0; i < k; i++) {
    int x, cost = 0;

    scanf("%d", &x);
#if (TYPE == 2)
      scanf("%d", &cost);
#endif

    v[START].push_back(make_pair(x, cost));
    v[x].push_back(make_pair(START, cost));
  }
  for (int i = 0; i < m; i++) {
    int x, y, cost;

    scanf("%d%d%d", &x, &y, &cost);

    v[x].push_back(make_pair(y, cost));
    v[y].push_back(make_pair(x, cost));
  }

  memset(cost, 0x3f, sizeof(cost));
  cost[START] = 0;
  in_queue[START] = false;
  queue<int> queue;
  queue.push(START);

  while (!queue.empty()) {
    int x = queue.front();
    queue.pop();
    in_queue[x] = false;

    for (unsigned int i = 0; i < v[x].size(); i++) {
      int next = v[x][i].first;

      if (cost[x] + v[x][i].second < cost[next]) {
        cost[next] = cost[x] + v[x][i].second;

        if (!in_queue[next]) {
          in_queue[next] = true;
          queue.push(next);
        }
      }
    }
  }

  for (int i = 1; i <= n; i++) {
    dists.push_back(make_pair(cost[i], i));
  }

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

  for (int i = n - 1; i >= 0; i--) {
    int x = dists[i].second;

    for (unsigned int j = 0; j < v[x].size(); j++) {
      int next = v[x][j].first;

      if (cost[next] >= dists[i].first) {
        unite(x, next, dists[i].first);
      }
    }
  }

  for (int i = 1; i <= q; i++) {
    int x, y, time;

    scanf("%d%d%d", &x, &y, &time);

    int cur_cost = 0;
    if (x == y) {
      cur_cost = cost[x];
    } else {
      part_cost[x] = 0x3f3f3f3f;
      for (; x; x = father[x]) {
        have_been[x] = i;
        part_cost[father[x]] = edge_cost[x];
      }
      for (; y; y = father[y]) {
        if (have_been[y] == i) {
          cur_cost = part_cost[y];
          break;
        }
        part_cost[father[y]] = min(part_cost[father[y]], edge_cost[y]);
      }
    }

    if (cur_cost < time) {
      printf("%d\n", 0);
    } else {
      printf("%d\n", cur_cost - time);
    }
  }

  return 0;
}