[LuoguP1119]灾后重建
感觉线代能上九十,开心
刷点水题
题意就是不停地往图里面加点和对应的边
然后询问点对的最短路长度
$n$个点 $q$次询问 $n\leq200,q\leq50000$
就是改改floyd就行了
floyd本质上是$f[i][j][k] = min(f[i][j][k], f[i][t][k-1]+f[t][j][k-1])$
每次加点的时候自己补上就行了
#include <bits/stdc++.h> using namespace std; const int maxn = 200 + 10, maxm = 40000 + 10, INF = 0x3f3f3f3f; int n, m; int t[maxn]; int g[maxn][maxn], dis[maxn][maxn]; int main(){ ios::sync_with_stdio(false); cin >> n >> m; for(int i = 0; i < n; i++){ cin >> t[i]; } memset(dis, 0x3f, sizeof dis); memset(g, 0x3f, sizeof g); int u, v, w; for(int i = 0; i < m; i++){ cin >> u >> v >> w; g[u][v] = g[v][u] = w; } for(int i = 0; i < n; i++){ g[i][i] = dis[i][i] = 0; } int last = -1, now; for(int i = 0; i < n; i++){ if(!t[i]){ for(int j = 0; j < i; j++){ dis[i][j] = dis[j][i] = g[i][j]; } last = i; } else break; } for(int k = 0; k <= last; k++){ for(int i = 0; i <= last; i++){ for(int j = 0; j <= last; j++){ dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); } } } int q, x, y, day; cin >> q; while(q--){ cin >> x >> y >> day; if(last == -1 || day > t[last]){ now = last + 1; while(now < n && t[now] <= day){ for(int i = 0; i < now; i++){ dis[i][now] = dis[now][i] = g[i][now]; } now++; } for(int k = last + 1; k < now; k++){ for(int i = 0; i < now; i++){ for(int j = 0; j < now; j++){ dis[k][i] = dis[i][k] = min(dis[k][i], dis[k][j] + dis[j][i]); } } for(int i = 0; i < now; i++){ for(int j = 0; j < now; j++){ dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); } } } last = now - 1; } if(dis[x][y] == INF) cout << -1 << endl; else cout << dis[x][y] << endl; } return 0; }