bzoj1123 割点性质应用
删掉无向图上任意一点,请求出将会增加的不连通的点对数
将无向图联通性的问题转化到搜索树方向上考虑
如果一个点不是割点,那么删掉该点的答案很简单,就是2*(n-1)
如果点u是割点,同时u在搜索树上有t个子节点,那么删掉u点后就会出现t+2个联通分量
1.t个包含不同子节点的联通分量:每个子节点联通分量的贡献是size[son]*(n-size[son])
2.结点u:u的贡献是(n-1)
3.剩下部分,即u子树除外其他的点形成的联通分量:这部分的贡献是n-1-sum{size[son]}
在tarjan时同时求出size数组即可
#include<bits/stdc++.h> using namespace std; #define maxn 500005 struct Edge{int to,nxt;}edge[maxn<<1]; int head[maxn],tot,n,m; long long ans[maxn]; void init(){ tot=0; memset(head,-1,sizeof head); } void addedge(int u,int v){ edge[tot].to=v; edge[tot].nxt=head[u]; head[u]=tot++; } int cut[maxn],low[maxn],dfn[maxn],size[maxn],ind; void tarjan(int u){ dfn[u]=low[u]=++ind; size[u]=1; int flag=0,sum=0; for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); size[u]+=size[v]; if(low[v]>=dfn[u]){ flag++; ans[u]+=(long long)size[v]*(n-size[v]); sum+=size[v]; if(u!=1 || flag>1) cut[u]=true;//u是割点 } } else low[u]=min(low[u],dfn[v]);//回边 } if(cut[u]) ans[u]+=(long long)(n-sum-1)*(sum+1)+(n-1);//加上剩余部分 else ans[u]=2*(n-1); } int main(){ init(); cin>>n>>m; for(int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); if(u==v)continue;//规定无重边 addedge(u,v); addedge(v,u); } tarjan(1); for(int i=1;i<=n;i++) printf("%lld\n",ans[i]); }