luogu P7516 [省选联考 2021 A/B 卷] 图函数
题面传送门
这个操作看上去很迷惑,考虑这个操作的本质是啥。
容易发现,如果\(u\)能通过标号大于等于\(u\)的点就可以走到\(v\),那么\(f(v,G)\)中\(u\)会使这个答案+1。
那么这个相当于每次对正反图bfs,都能遍历到的点就在一个强连通分量中。就计入答案。
但是题目还要求我们对前缀删边的图进行求值。
发现每对点只会进行一次对答案的贡献,那么记第\(i\)条边的删除时间为\(i\),一条路径的权值为路径上边的最小值,就是要求\(u,v\)间的最大路径,然后对所有时间小于这个时间的答案都加一。
如果从大往小扫这些点,那么这些点依次被允许转移,容易发现这个与Floyd的转移类似。所以只要跑一个Floyd即可。
时间复杂度\(O(n^3+m)\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N (1000+5)
#define M (200000)
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,m,k,x,y,Fl[M+5],F[N+5][N+5];
int main(){
freopen("1.in","r",stdin);
RI i,j,h;scanf("%d%d",&n,&m);for(i=1;i<=n;i++) F[i][i]=m+1;for(i=1;i<=m;i++) scanf("%d%d",&x,&y),F[x][y]=i;
for(h=n;h;h--){
for(i=1;i<=n;i++) {if(!F[i][h])continue;for(j=1;j<=n;j++) F[i][j]=max(F[i][j],min(F[i][h],F[h][j]));}for(i=h;i<=n;i++) min(F[h][i],F[i][h])&&(Fl[min(F[h][i],F[i][h])-1]++,0);
}for(i=m;~i;i--) Fl[i]+=Fl[i+1];for(i=0;i<=m;i++) printf("%d ",Fl[i]);
}