题意简述
给一个有向图,有两个操作,一个是删除一条边,一个是询问两点之间最短路,(n le 200,q le 100000),其中操作一(删边)不超过(200)次。
一个反向操作的 ( exttt{trick}),相当于先把所有要删的边删除,形成一个新图(mathbf{G}'),对(mathbf{G}')先(operatorname{Floyd}),后反向进行加边(( exttt{add Edge}))操作,每次加边更新(f_{i,j}),(f_{i,j} = min(f_{i,j},f_{i,u} + f_{v,j} + f_{u,v})),其中((u,v,w))为新加边。
时间复杂度(mathcal{O}(n^3 + 200n^2))
#include <bits/stdc++.h>
using namespace std;
const int N = 205;
const long long inf = 5e11;
int n, m;
struct node
{
int opt, x, y;
};
long long f[N][N], f2[N][N];
int vis[N][N];
long long ans[100005];
int top = 0;
node q[100005];
void FIO(void)
{
freopen("journey.in", "r", stdin);
freopen("journey.out", "w", stdout);
return;
}
void update(int u, int v)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
f[i][j] = min(f[i][j], f[i][u] + f[v][j] + f[u][v]);
}
}
return;
}
int main(void)
{
FIO();
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
f[i][j] = f2[i][j] = (i == j) ? 0 : inf;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
scanf("%lld", &f[i][j]);
f2[i][j] = f[i][j];
}
}
for (int i = 1; i <= m; i++)
{
scanf("%d%d%d", &q[i].opt, &q[i].x, &q[i].y);
if (q[i].opt == 1)
{
if (vis[q[i].x][q[i].y] == 0)
vis[q[i].x][q[i].y] = i;
f[q[i].x][q[i].y] = inf;
}
}
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
}
}
}
for (int i = m; i >= 1; i--)
{
int u = q[i].x, v = q[i].y;
if (q[i].opt == 1)
{
if (vis[u][v] != i)
continue;
f[u][v] = min(f[u][v], f2[u][v]);
update(u, v);
}
else
{
ans[++top] = f[u][v];
}
}
for (int i = top; i >= 1; i--)
printf("%lld
", (ans[i] >= inf) ? -1 : ans[i]);
return 0;
}