[省选 2021] 图函数

直接想没有思路的时候看怎么转化题意。
先手动模拟一次,发现当函数执行到 v=u 时,u 自己就被删掉了,所以 cnt 不会变化了。同时,到 v 的时候,1v1 都被删了,所以只能经过 v 的点。所以翻译下 f(u) 就是图中满足 [uv](v),vuv 的个数,其中定义 [uv] 表示 u,v 可以通过 v 的点互达。([uu]=1
而所有时候我们需要的都是 f(u),因此 vu 的条件可以去掉,转为求 f=u,v[uv](min(u,v))
先考虑第一问(图完整)。观察到 [] 为一种连通性关系,floyd 是用来求解此类问题的,再考虑如何解决所经点限制,floyd 有专门的一个循环来枚举所经点,当外层 k 从大到小枚举并在内层两个循环中加一些 if 就容易满足。
再考虑求出每个图,由于是边的有无影响了连通性,重要一点在于想到转化为(用 floyd)维护 一个点能到另一个点的最早时间,即最大的 i 使加入第 [i,m] 条边后一个点可以到达另一个点

启示:

  1. 有关连通性的题目可以想 floyd
  2. 每次只改动一条边或类似情况,有时间轴思想、整体处理
  3. 图中类似于函数的叙述,力求破译其本质

轻微卡常即可写出代码。复杂度 O(n3)

复制
#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(' ');
}
posted @   pengyule  阅读(30)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示