D109 最短路 Floyd 算法 P7516 [省选联考 2021 A/B 卷] 图函数
D109 最短路 Floyd 算法 P7516 [省选联考 2021 AB 卷] 图函数_哔哩哔哩_bilibili
P7516 [省选联考 2021 A/B 卷] 图函数 - 洛谷
给一个有向图 $G$,定义 $f(u,G)$ 如下:
1. 令 $cnt=0,G'=G$
2. 按从小到大的顺序枚举每个点 $v$,若在 $G'$ 中 $u,v$ 互达,则令 $cnt++$,并在 $G'$ 中删去 $v$ 以及邻边
3. $f(u,G)=cnt$
定义 $h(G)=\sum f(i,G)$。再定义 $G_i$ 为删去 $G$ 中前 $i$ 条边后的图,求所有 $h(G_i)$

思路
观察发现,每个点都会自达而产生贡献,每个点只能通过更大的点互达而产生贡献(因为更小的点已经删除了)
考虑 $k$ 点的贡献,就是考虑 $k$ 与 $[k,n]$ 之间哪些点互达,而要排除小于 $k$ 的点做通道
我们用 Floyd 跑可达性,逆序枚举插点 k,就可以保证这一点
删边不易操作,考虑倒序加边,给加边按时间序编号,把上图倒放“电影”(从右向左),加边越晚贡献越少
设 $f(i,j)$ 表示 $i$ 可达 $j$ 的最早时间,$s[f(k,i)]$ 记录 $k$ 与 $i$ 互达时刻的贡献,求 $h(G_i)$ 就是求 $s[i]$ 的前缀和

图中,4个点都是时刻 0 时自达,对所有图都有贡献;
$[1\;2],[1\;3]$ 都是时刻 4 时互达,对中图、左图都有贡献;$[2\;3],[2\;4],[1\;4]$ 都是时刻 5 时互达,只对左图有贡献

相关板子:
D04【模板】最短路 Floyd 算法 - 董晓 - 博客园
// 最短路+逆向思维 Floyd 算法 O(N^3) #include<bits/stdc++.h> #define min(x,y) (x<y?x:y) //比库函数快 #define max(x,y) (x>y?x:y) using namespace std; const int N=1010,M=200005; int n,m; int f[N][N],s[M]; int main(){ scanf("%d%d",&n,&m); memset(f,0x3f,sizeof f); for(int i=1; i<=n; i++)f[i][i]=0; //点自己0时刻互达 for(int i=1,x,y; i<=m; i++){ scanf("%d%d",&x,&y); f[x][y]=m-i+1; //x可达y的最早时间(倒序加边的时间) } for(int k=n; k; k--){ //逆序枚举插点 for(int i=1; i<=n; i++)if(f[i][k]<M) //如果i可达k for(int j=1; j<=n; j++) f[i][j]=min(f[i][j],max(f[i][k],f[k][j])); //更新i可达j的最早时间 for(int i=k; i<=n; i++) if(max(f[k][i],f[i][k])<M) s[max(f[k][i],f[i][k])]++; //累计k与i互达时刻的贡献 } for(int i=1; i<=m; i++) s[i]+=s[i-1]; //贡献的前缀和 for(int i=m; i>=0; i--) printf("%d ",s[i]); //逆序输出 }
浙公网安备 33010602011771号