$\rm Sol.$
首先考虑分析 $f(u, G)$
-
会产生贡献的 $v$ 必须满足 $v < u.$
-
$v$ 与 $u$ 会产生贡献当且仅当 $u$ 和 $v$ 可以仅通过大于 $v$ 的点互达
。
$\rm Proof: $
- 当 $v > u$ 时 $u$ 自己都已经删掉了
肯定不能产生贡献 , 。 如上图所示
我们不妨设 $u \to v$ 的路径上必须经过 $x(x < u)$ , 那么 $x$ 和 $u$ 一定相互可达 , $x$ 会在统计 $v$ 的答案之前被删掉 , 。
于是我们可以发现
我们考虑 $\rm Floyd$ 算法的过程
进一步观察发现
最后用差分维护一下就可以得到最终答案
时间复杂度 $\Theta(n ^ 3 + m)$
为了进一步优化复杂度
考虑按编号从大到小枚举所有的边
首先计算 $v$ 可以到达 $u$ 的分界点
有两个显然的性质
- 有贡献的点对数量最多 $n ^ 2$ 量级
。 - 在加边的过程中有贡献的点对数量不减
。
于是考虑计算每条边加入后有贡献的点对的增量
如上图所示
考虑用 $\rm bitset$ 记录某个点能直接到达的所有点
可以发现
- $u$ 在加入 $x \to y$ 之前不能到达 $y.$
- $u$ 在加入 $x \to y$ 之前要能到达 $x.$
- 路径上所有点的编号都不小于 $u.$
首先前两个条件可以通过 $T_x \cap (U - T_y)$ 简单地得到
考虑这样做的复杂度为什么是对的
$\rm Code$
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10, M = 2e5 + 10;
int n, m, E[N][N], ans[M], Eik, tmp;
int main () {
scanf("%d%d", &n, &m);
for (int u, v, i = 1; i <= m; i++)
scanf("%d%d", &u, &v), E[u][v] = i;
for (int k = n; k >= 1; k--) {
for (int i = 1; i <= n; i++) if (E[i][k]) {
int j;
for (j = 1; j + 7 <= n; j += 8) {
Eik = E[i][k];
tmp = Eik < E[k][j] ? Eik : E[k][j];
E[i][j] = E[i][j] > tmp ? E[i][j] : tmp;
tmp = Eik < E[k][j + 1] ? Eik : E[k][j + 1];
E[i][j + 1] = E[i][j + 1] > tmp ? E[i][j + 1] : tmp;
tmp = Eik < E[k][j + 2] ? Eik : E[k][j + 2];
E[i][j + 2] = E[i][j + 2] > tmp ? E[i][j + 2] : tmp;
tmp = Eik < E[k][j + 3] ? Eik : E[k][j + 3];
E[i][j + 3] = E[i][j + 3] > tmp ? E[i][j + 3] : tmp;
tmp = Eik < E[k][j + 4] ? Eik : E[k][j + 4];
E[i][j + 4] = E[i][j + 4] > tmp ? E[i][j + 4] : tmp;
tmp = Eik < E[k][j + 5] ? Eik : E[k][j + 5];
E[i][j + 5] = E[i][j + 5] > tmp ? E[i][j + 5] : tmp;
tmp = Eik < E[k][j + 6] ? Eik : E[k][j + 6];
E[i][j + 6] = E[i][j + 6] > tmp ? E[i][j + 6] : tmp;
tmp = Eik < E[k][j + 7] ? Eik : E[k][j + 7];
E[i][j + 7] = E[i][j + 7] > tmp ? E[i][j + 7] : tmp;
}
for ( ; j <= n; ++j) E[i][j] = max(E[i][j], min(E[i][k], E[k][j]));
}
for (int u = k + 1; u <= n; u++)
ans[min(E[u][k], E[k][u]) - 1]++;
}
for (int i = m; i >= 0; i--) ans[i] += ans[i + 1];
for (int i = 0; i <= m; i++) printf("%d ", ans[i] + n);
return 0;
}