1. 程式人生 > >BZOJ BLO 1123 (割點)【雙連通】

BZOJ BLO 1123 (割點)【雙連通】

flag hysbz 如果 font 能夠 根節點 至少 其它 min

<題目鏈接>

題目大意:
現在給定一張連通的無向圖,不包含重邊。現在輸出$n$個整數,表示將第$i$個節點的所有與其它節點相關聯的邊去掉之後(不去掉$i$節點本身),無向圖中有多少個有序對$(u,v)$,滿足$u,v$不連通。
解題分析:
首先,很明顯,$i$節點是需要分成割點和非割點來進行討論的。
對於非割點i來說,去除$i$周圍的所有邊之後,只有$i$點和其它$n-1$個點不連通,所以增加的有序對為$2*(n-1)$個。

對於割點$i$來說,假設在搜索樹上,節點i有$t$個子樹,則至多能夠夠分成$t+2$個連通塊,每個連通塊的節點構成情況為:
1.節點$i$獨自構成一個連通塊
2.有$t$個連通塊,分別由搜索樹上$i$的$t$個子樹的所有節點分別構成


3.還有除上述所有節點之外的點構成(比如在搜索樹上,$i$節點父親方向的所有節點)
割點有序對的所有情況就能夠依據上面幾種情況求出,這裏就不再進行贅述。

割點的判定法則:
u是割點當且僅當搜索樹上存在的一個子節點v,滿足:$$low[v]>=dfn[u]$$
特別地,如果u是搜索樹上的根節點,則u是割點當且僅當存在至少兩個子節點滿足上述條件。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 1e5+5, M = 5e5+5;
struct Edge{
    
int to,nxt; }edge[M<<1]; int n,m,cnt,tot,head[N],dfn[N],low[N],sz[N]; bool cut[N]; ll ans[N]; void addedge(int u,int v){ edge[++cnt].to=v,edge[cnt].nxt=head[u]; head[u]=cnt; } void Tarjan(int u){ dfn[u]=low[u]=++tot;sz[u]=1; int flag=0,sum=0; for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to; if(!dfn[v]){ Tarjan(v); sz[u]+=sz[v]; low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]){ //如果滿足割點的條件 flag++; ans[u]+=(ll)(sz[v])*(n-sz[v]); //v所在的連通分量與其它所有點構成的有序對數量 sum+=sz[v]; if(u!=1 || flag>1)cut[u]=true; } }else low[u]=min(low[u],dfn[v]); } if(cut[u])ans[u]+=(ll)(sum+1)*(n-sum-1)+(n-1); //父親方向的點與其它點構成的有序對 以及 i節點獨自與其它節點構成的有序對 else ans[u]=2*(n-1); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int u,v;scanf("%d%d",&u,&v); addedge(u,v);addedge(v,u); } Tarjan(1); //因為這是無向圖,並且所有的點連通 for(int i=1;i<=n;i++) printf("%lld\n",ans[i]); }

2019-03-01

BZOJ BLO 1123 (割點)【雙連通】