灾后重建
luogu 1119
题目大意
给你一个图,每个点在一定时间后才能被通过,问在某个时间,两个点之间的最短路
输入样例
4 5
1 2 3 4
0 2 1
2 3 1
3 1 2
2 1 4
0 3 5
4
2 0 2
0 1 2
0 1 3
0 1 4
输出样例
-1
-1
5
4
数据范围
N⩽200,M⩽N×(N−1)2,Q⩽50000N\leqslant 200,M\leqslant \frac{N \times (N-1)}{2},Q\leqslant 50000N⩽200,M⩽2N×(N−1),Q⩽50000
解题思路
题目保证每个点的通行时间是单调递增的
那么可以离线处理
当连上一个点后再以这个点为中间点跑FloydFloydFloyd
输出的时候判断一下两个点的通行时间是否小于查询时间即可
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 210
#define Q 50010
using namespace std;
ll n, m, x, y, z, q, qt, t[N], a[N][N];
struct node
{ll x, y, t, ans;
}ask[Q];
ll read()
{ll ds = 0, fs = 1;char c = getchar();while(c < '0' || c > '9') {if (c == '-') fs = -1; c = getchar();}while('0' <= c && c <= '9') ds = (ds<<1) + (ds<<3) + c - 48, c = getchar();return ds * fs;
}
void writ(ll x)
{if (x / 10) writ(x / 10);putchar(x % 10 + 48);
}
void write(ll x)
{if (x < 0) putchar('-'), x = -x;writ(x);putchar(10);return;
}
int main()
{memset(a, 127/3, sizeof(a));n = read();m = read();for (ll i = 0; i < n; ++i)t[i] = read();for (ll i = 1; i <= m; ++i){x = read();y = read();z = read();a[x][y] = min(a[x][y], z);a[y][x] = min(a[y][x], z);}q = read();for (ll i = 1; i <= q; ++i){ask[i].x = read();ask[i].y = read();ask[i].t = read();}qt = 1;for (ll k = 0; k < n; ++k){while(ask[qt].t < t[k] && qt <= q)//离线处理{ask[qt].ans = a[ask[qt].x][ask[qt].y];qt++;}for (ll i = 0; i < n; ++i)for (ll j = 0; j < n; ++j)a[i][j] = min(a[i][j], a[i][k] + a[k][j]);//Floyd}while(qt <= q){ask[qt].ans = a[ask[qt].x][ask[qt].y];qt++;}for (ll i = 1; i <= q; ++i)if (ask[i].t < t[ask[i].x] || ask[i].t < t[ask[i].y] || ask[i].ans > 2000000) write(-1);//判断是否可以通行else write(ask[i].ans);return 0;
}