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]$ 的前缀和

image

图中,4个点都是时刻 0 时自达,对所有图都有贡献;

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

image

相关板子:

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]); //逆序输出
}

 

posted @ 2026-03-21 11:30  董晓  阅读(39)  评论(0)    收藏  举报