【dfs+连通分量】Bzoj1123 POI2008 BLO

Description

Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通。

Input

输入n<=100000 m<=500000及m条边

Output

输出n个数,代表如果把第i个点去掉,将有多少对点不能互通。

 

Solution

求割顶的一系列操作不仅可以用来求割顶,也可以解决很多问题,比如这道题。

dfs是很神奇的,对于节点u能扩展出去的v的子树是互相独立的,反向边也只会往上连。

那么对于u,他的父亲p和能连回去的v形成一个连通块,其余v各成一个连通块。

然后就很好统计了(细节自己想),其实用dfs树来处理大概就是树形dp。

 

Code

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define ll long long
 4 using namespace std;
 5 const int maxn=1e5+5,maxm=1e6+5;
 6 
 7 int pre[maxn],low[maxn],clock;
 8 int head[maxn],e[maxm],nxt[maxm],cnt;
 9 int adde(int u,int v){
10     e[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
11     e[++cnt]=u;nxt[cnt]=head[v];head[v]=cnt;
12 }
13 ll ans[maxn],t[maxn];
14 int n,m,size[maxn];
15 
16 int dfs(int u){
17     pre[u]=low[u]=++clock;
18     size[u]=1;
19     for(int i=head[u];i;i=nxt[i]){
20         int v=e[i];
21         if(pre[v]) low[u]=min(low[u],pre[v]);
22         else{
23             dfs(v);
24             size[u]+=size[v];
25             low[u]=min(low[u],low[v]);
26             if(low[v]>=pre[u]){
27                 ans[u]+=t[u]*size[v];
28                 t[u]+=size[v];
29             }
30         }
31     }
32     ans[u]+=t[u]*(n-t[u]-1);
33     ans[u]=(ans[u]+n-1)*2;
34 }
35 
36 int main(){
37     scanf("%d%d",&n,&m);
38     int u,v;
39     for(int i=1;i<=m;i++){
40         scanf("%d%d",&u,&v);
41         adde(u,v);
42     }
43     
44     for(int i=1;i<=n;i++)
45         if(!pre[i]) dfs(i);
46         
47     for(int i=1;i<=n;i++)
48         printf("%lld\n",ans[i]);
49     return 0;
50 }
View Code

 

posted @ 2015-06-04 21:53  CyanNode  阅读(265)  评论(0编辑  收藏  举报