【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 }