版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/niiick/article/details/82892325
Time Limit: 10 Sec
Memory Limit: 162 MB
Description
Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通。
Input
输入n<=100000 m<=500000及m条边
Output
输出n个数,代表如果把第i个点去掉,将有多少对点不能互通。
题目分析
若结点
不是割点,那么去掉他只有
和其他
个点不连通
若结点
是割点,则需要 将去掉
后产生的连通块两两相乘累加进入答案
Tarjan求割点的过程其实是一个建立搜索树的过程,我们可以从这里入手
假设搜索树上结点
的子节点集合为
,其中有
个点满足其是割点
那么去掉
后将产生至多
个连通块
1.结点
单独在一个连通块
2.搜索树上
的
个满足割点判断的点与他们自己的子树各自构成一个连通块
3.若搜索树上
的子节点数量大于k,那么剩下的点构成一个连通块
由此我们可以在Trajan的过程中顺便记录搜索树上每个子树的大小size[u]
那么去掉
后产生的不连通的有序对数量为
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;
lt read()
{
lt f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
void print(lt x)
{
if(x<0){putchar('-');x=-x;}
if(x>9)print(x/10);
putchar(x%10+'0');
}
lt n,m;
lt tot,cnt;
struct node{lt v,nxt;}E[1000010];
lt head[100010];
lt ans[100010];
lt dfn[100010],low[100010];
lt size[100010];
bool cut[100010];
lt rt;
void add(lt u,lt v)
{
E[++tot].nxt=head[u];
E[tot].v=v;
head[u]=tot;
}
void tarjan(lt u)
{
dfn[u]=low[u]=++cnt; size[u]=1;
lt flag=0,sum=0;
for(lt i=head[u];i;i=E[i].nxt)
{
lt v=E[i].v;
if(!dfn[v])
{
tarjan(v);
size[u]+=size[v];
low[u]=min(low[u],low[v]);
if(dfn[u]<=low[v])
{
flag++;
ans[u]+=size[v]*(n-size[v]);
sum+=size[v];
if(u!=rt||flag>1) cut[u]=true;
}
}
else low[u]=min(low[u],dfn[v]);
}
if(cut[u]) ans[u]+=(n-sum-1)*(sum+1)+n-1;
else ans[u]=2*(n-1);
}
int main()
{
n=read();m=read();
for(lt i=1;i<=m;i++)
{
lt u=read(),v=read();
if(u==v) continue;
add(u,v);add(v,u);
}
for(lt i=1;i<=n;i++)
if(!dfn[i]) rt=i,tarjan(i);
for(lt i=1;i<=n;i++)
print(ans[i]),printf("\n");
return 0;
}