题目描述
对于一张 n 个点 m 条边的有向图 G(顶点从 1∼n 编号),定义函数 f(u,G):
- 初始化返回值 cnt=0,图 G′=G。
- 从 1 至 n 按顺序枚举顶点 v,如果当前的图 G′ 中,从 u 到 v 与从 v 到 u 的路径都存在,则将 cnt+1,并在图 G′ 中删去顶点 v 以及与它相关的边。
- 第 2 步结束后,返回值 cnt 即为函数值。
现在给定一张有向图 G,请你求出 h(G)=f(1,G)+f(2,G)+⋯+f(n,G) 的值。
更进一步地,记删除(按输入顺序给出的)第 1 到 i 条边后的图为 Gi(1≤i≤m),请你求出所有 h(Gi) 的值。
输入格式
第一行,两个整数 n,m,表示图的点数与边数。
接下来 m 行,每行两个整数,第 i 行的两个整数 xi,yi 表示一条有向边 xi→yi。
数据保证 xi=yi 且同一条边不会给出多次。
输出格式
输出一行 m+1 个整数,其中第一个数表示给出的完整图 G 的 h(G) 值。第 i(2≤i≤m+1)个整数表示 h(Gi−1)。
输入输出样例
输入 #1复制
4 6
2 3
3 2
4 1
1 4
2 1
3 1
输出 #1复制
6 5 5 4 4 4 4
输入 #2复制
见附件中的 graph/graph2.in。
输出 #2复制
见附件中的 graph/graph2.ans。
说明/提示
【样例 #1 解释】
对于给出的完整图 G:
- f(1,G)=1,过程中删除了顶点 1。
- f(2,G)=1,过程中删除了顶点 2。
- f(3,G)=2,过程中删除了顶点 2,3。
- f(4,G)=2,过程中删除了顶点 1,4。
【数据范围】
对于所有测试数据:2≤n≤103,1≤m≤2×105,1≤xi,yi≤n。
每个测试点的具体限制见下表:
| 测试点编号 | n≤ | m≤ |
|---|---|---|
| 1∼4 | 10 | 10 |
| 5∼11 | 100 | 2×103 |
| 12∼20 | 103 | 5×103 |
| 21∼25 | 103 | 2×105 |
附件下载
graph.zip3.51KB
代码实现:
#include<stdio.h>
const int N=1005,M=200005;
int n,m;
int g[N][N],s[M],a[M];
inline int min(int a,int b){
return a<b? a:b;
}
inline int max(int a,int b){
return a>b? a:b;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
g[i][i]=m+1;
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
g[x][y]=i;
}
for(int k=n;k>=1;k--){
for(int i=k;i<=n;i++)
s[min(g[i][k],g[k][i])]++;
for(int i=1;i<=k;i++)
if(g[i][k])
for(int j=1;j<=n;j++)
g[i][j]=max(g[i][j],min(g[i][k],g[k][j]));
for(int i=k+1;i<=n;i++)
if(g[i][k])
for(int j=1;j<k;j++)
g[i][j]=max(g[i][j],min(g[i][k],g[k][j]));
}
for(int i=m;i>=1;i--)
s[i]+=s[i+1];
for(int i=1;i<=m+1;i++)
printf("%d%c",s[i],i==m+1? '\n':' ');
return 0;
}