题目链接

题目描述

Greg有一个有边权的有向图,包含 \(n\) 个点。这个图的每两个点之间都有两个方向的边。Greg喜欢用他的图玩游戏,现在他发明了一种新游戏:

  • 游戏包含 \(n\) 步。
  • \(i\) 步Greg从图中删掉编号为 \(x_i\) 的点。当删除一个点时,这个点的出边和入边都会被删除。
  • 在执行每一步之前,Greg想知道所有点对间最短路长度的和。最短路可以经过任何没删掉的点。换句话说,如果我们假设 \(d(i, v, u)\) 是在删掉 \(x_i\)\(v\)\(u\) 间的最短路长度,那么Greg想知道下面这个求和的值:\[\sum_{v, u, v \neq u} d(i, v, u)\]

帮帮Greg,输出每一步之前要求的值。

Input / Output 格式 & 样例

输入格式

第一行包含一个整数 \(n \ (1 \leq n \leq 500)\) ,代表图中的点数。

下面 \(n\) 行每行包含 \(n\) 个整数,代表边权:第 \(i\) 行的第 \(j\) 个数 \(a_{ij} \ (1 \leq a_{ij} \leq 10^5, a_{ii} = 0)\) 代表从 \(i\)\(j\) 的边权。

最后一行包含 \(n\) 个整数: \(x_1, x_2, \dots, x_n \ (1 \leq x_i \leq n)\) ,分别为Greg每一步删掉的点的编号。

输出格式

输出 \(n\) 个整数,第 \(i\) 个数等于游戏的第 \(i\) 步之前统计的求和值。

请不要在C++中使用%lld标志来输出64位整数long long,推荐使用cin, cout流或者用%I64d标志。

输入样例

Case #1:

1
0
1

Case #2:

2
0 5
4 0
1 2

Case #3:

4
0 3 1 1
6 0 400 1
2 4 0 1
1 1 1 0
4 1 2 3

输出格式

Case #1:

0

Case #2:

9 0

Case #3:

17 23 404 0

解析

\(n \le 500\)

很明显跑 Floyd 了

但是 Floyd 不支持删除操作

怎么办?

倒序添加!

我们记录下删除点的信息,再倒着添加回去,在这个过程中套一个 Floyd 进去

要注意的是累计答案的时候判断点是否存在

代码实现

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
using namespace std;

const int MAXN = 500 + 10;

int f[MAXN][MAXN];
int seq[MAXN];
long long int ans[MAXN];

bool inGraph[MAXN];

int n;

inline int getint() {
    int s = 0, x = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') x = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        s = s * 10 + ch - '0';
        ch = getchar();
    }
    return s * x;
}

inline void putint(int x, bool returnValue) {
    if (x < 0) {
        x = -x;
        putchar('-');
    }
    if (x >= 10) putint(x / 10, false);
    putchar(x % 10 + '0');
    if (returnValue) putchar('\n');
}

inline void addEdge(int s, int t, int w) {
    f[s][t] = f[t][s] = w;
}

int main(int argc, char *const argv[]) {
    n = getint();
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            f[i][j] = getint();
        }
    }
    for (int i = 1; i <= n; ++i) {
        seq[i] = getint();
    }
    for (int l = n; l > 0; --l) {
        int k = seq[l];
        inGraph[k] = true;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                f[i][j] = std::min(f[i][j], f[i][k] + f[k][j]);
                if (inGraph[i] && inGraph[j]) ans[l] += f[i][j];
            }
        }
    }
    for (int i = 1; i <= n; ++i) cout << ans[i] << ' ';
    return 0;
}



01-03 07:19