1. 程式人生 > >【bzoj1123】BLO

【bzoj1123】BLO

1123: [POI2008]BLO

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2222  Solved: 1090
[Submit][Status][Discuss]

Description

Byteotia城市有n個 towns m條雙向roads. 每條 road 連線 兩個不同的 towns ,沒有重複的road. 所有towns連通。

Input

輸入n<=100000 m<=500000及m條邊

Output

輸出n個數,代表如果把第i個點去掉,將有多少對點不能互通。

Sample Input

5 5
1 2
2 3
1 3
3 4
4 5

Sample Output

8
8
16
14
8

HINT

Source

 

題意:

極其簡潔啊……

 

題解:

縮完點雙後原圖會變為一棵樹。

每刪掉一個割點,它的子樹之間兩兩不能連線,子樹與子樹外的點兩兩不能連線。

然後驚奇的發現這題的點對要算上被刪去的那個點。GG。

 

程式碼:

#include<algorithm>
#include<iostream>
#include<cstring>
#include
<cstdio> using namespace std; #define MAXN 100005 #define MAXM 500005 #define INF 0x7fffffff #define ll long long ll hd[MAXN],to[MAXM<<1]; ll nxt[MAXM<<1],siz[MAXN]; ll dfn[MAXN],low[MAXN]; ll N,M,ans[MAXN],cnt,num; inline ll read(){ ll x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar())
if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline void tarjan(ll u){ dfn[u]=low[u]=++num; ll cutnum=0;siz[u]=1; for(ll i=hd[u];i;i=nxt[i]){ ll v=to[i]; if(dfn[v]) low[u]=min(low[u],dfn[v]); else{ tarjan(v);siz[u]+=siz[v]; low[u]=min(low[u],low[v]); if(dfn[u]<=low[v]){ ans[u]+=(cutnum*siz[v]); cutnum+=siz[v]; } } } ans[u]+=(cutnum*(N-cutnum-1)); return; } inline void addedge(ll u,ll v){ to[++cnt]=v,nxt[cnt]=hd[u]; hd[u]=cnt;return; } int main(){ N=read(),M=read(); for(ll i=1;i<=M;i++){ ll u=read(),v=read(); addedge(u,v),addedge(v,u); } for(ll i=1;i<=N;i++) if(!dfn[i]) tarjan(i); for(ll i=1;i<=N;i++) printf("%lld\n",ans[i]*2+(N-1)*2); return 0; }