正题
题目大意
求每个点是多少个点对之间路径的必经点。
解题思路
首先若一个点是在点不是割点,那么答案就是n−1n-1n−1,因为这个点不是除了它自己以为任何点对的必经点。
之后我们记录每个可以割掉的联通分量的大小。对于一个割点,是两种路径的必经点。
- 从外连入内
- 这个点连接的点双之间互相到达
分开计算就好了。
codecodecode
#include<cstdio>
#include<stack>
#include<queue>
#include<cstring>
#define N 50010
using namespace std;
struct line{int to,next;
}a[N*4];
int tot,ls[N],siz[N],dfn[N],low[N],num,n,ans[N],m;
bool v[N];
void addl(int x,int y)
{a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;
}
void tarjan(int x,int fa)//tarjan
{dfn[x]=low[x]=++num;int L=0;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;v[y]=0;if(!dfn[y]){tarjan(y,x);siz[x]+=siz[y];if(dfn[x]<=low[y])L+=siz[y];v[y]=1;}if(y!=fa)low[x]=min(low[y],low[x]);}//以上求low和dfn以判断割点int A=0,B=0;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(dfn[x]<=low[y]&&v[y]){A+=(L-siz[y])*siz[y];//点内互相到达B+=(n-L-1)*siz[y];//外连内}}A/=2;ans[x]=A+B+n-1;
}
int main()
{freopen("data.in","r",stdin);freopen("data.out","w",stdout);scanf("%d%d",&n,&m);for (int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);addl(x,y);addl(y,x);}num=0;for(int i=1;i<=n;i++)siz[i]=1;tarjan(1,0);for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
}