给定一张无向图,求每个点被封锁之后有多少个有序点对(x,y)(x!=y,1<=x,y<=n)满足x无法到达y
首先不是割点答案为2*(n-1),是割点就要考虑删掉割点会分开哪些连通块
考虑tarjan的过程,核心是对搜索树的处理,如果是割点的话删除掉点x会产生的连通块为x的所有以儿子为根的子树和x子树外的所有部分,每个子树产生的贡献为$size[s1]*(n-size[s1])$,x子树外的贡献为$(size[x])*(n-size[x])$,以及x自己的为$(n-1)$
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=100009; const int maxm=500009; int n,m,tim,root; struct node{ int v,nxt; }e[maxm<<1]; int head[maxn],cnt=1; inline void add(int u,int v){ e[++cnt].v=v;e[cnt].nxt=head[u];head[u]=cnt; } int dfn[maxn],low[maxn];bool cut[maxn]; ll ans[maxn],sz[maxn]; void tarjan(int x){ dfn[x]=low[x]=++tim;sz[x]=1; int son=0,sum=0; for(int i=head[x];i;i=e[i].nxt){ int y=e[i].v; if(!dfn[y]){ tarjan(y);sz[x]+=sz[y]; low[x]=min(low[x],low[y]); if(low[y]>=dfn[x]){ son++; ans[x]+=sz[y]*(n-sz[y]);//每个点只能到当前子树内的点 sum+=sz[y]; if(x!=root||son>1)cut[x]=1; } } else low[x]=min(low[x],dfn[y]); } if(cut[x])ans[x]+=1ll*(n-sum-1)*(sum+1)+(n-1);//x子树外的不能到x子树内的且x不能到其他所有点 else ans[x]=2*(n-1); } int main(){ scanf("%d%d",&n,&m); for(int i=1,u,v;i<=m;i++){ scanf("%d%d",&u,&v);if(u==v)continue; add(u,v);add(v,u); } for(int i=1;i<=n;i++) if(!dfn[i])root=i,tarjan(i); for(int i=1;i<=n;i++)printf("%lld\n",ans[i]); }