题解 P7516 [省选联考 2021 A/B 卷] 图函数
直接想没有思路的时候看怎么转化题意。
先手动模拟一次,发现当函数执行到 k 从大到小枚举并在内层两个循环中加一些 if 就容易满足。
再考虑求出每个图,由于是边的有无影响了连通性,重要一点在于想到转化为(用 floyd)维护 一个点能到另一个点的最早时间,即最大的
启示:
- 有关连通性的题目可以想 floyd
- 每次只改动一条边或类似情况,有时间轴思想、整体处理
- 图中类似于函数的叙述,力求破译其本质
轻微卡常即可写出代码。复杂度
#include <bits/stdc++.h>
using namespace std;
const int N=1005,M=2e5+5;
int n,m,f[N][N],ans[M];
inline int read(){
register char ch=getchar();register int x=0;
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
void print(int x){
if(x/10)print(x/10);
putchar(x%10+48);
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)f[i][i]=m+1;
for(int i=1,u,v;i<=m;i++)u=read(),v=read(),f[u][v]=i;
for(int k=n;k;k--){
for(int i=1;i<=k;i++)
for(int j=1;j<=n;j++){
if(f[i][k]&&f[k][j])f[i][j]=max(f[i][j],min(f[i][k],f[k][j]));
}
for(int i=k+1;i<=n;i++)
for(int j=1;j<=k;j++){
if(f[i][k]&&f[k][j])f[i][j]=max(f[i][j],min(f[i][k],f[k][j]));
}
}
for(int i=1;i<=n;i++)for(int j=i;j<=n;j++)ans[min(f[i][j],f[j][i])]++;
for(int i=m;i;i--)ans[i]+=ans[i+1];
for(int i=1;i<=m+1;i++)print(ans[i]),putchar(' ');
}