[模拟赛20180809] 旅程

题意简述

给一个有向图,有两个操作,一个是删除一条边,一个是询问两点之间最短路,\(n \le 200,q \le 100000\),其中操作一(删边)不超过\(200\)次。

一个反向操作的 \(\texttt{trick}\),相当于先把所有要删的边删除,形成一个新图\(\mathbf{G}'\),对\(\mathbf{G}'\)\(\operatorname{Floyd}\),后反向进行加边(\(\texttt{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\n", (ans[i] >= inf) ? -1 : ans[i]);
    return 0;
}
posted @ 2020-10-20 23:31  luyiming123  阅读(52)  评论(0编辑  收藏  举报