[模拟赛20180809] 旅程

题意简述

给一个有向图,有两个操作,一个是删除一条边,一个是询问两点之间最短路,(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;
}