BZOJ1123: [POI2008]BLO
正文索引 [隐藏]
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
题解
求割点,一个简单的方法就是使用Tarjan。
我们在Tarjan的同时考虑一条树枝边(u,v),即u为v的父亲。此时dfn[u]<=low[v],即其儿子v无法到达比起标号更小的节点,那么这个点就是一个割点。统计的时候主要在每个点第一次访问的时候统计!
至于答案的统计嘛!主要要算上去掉的点与其他所有点都不连通的贡献。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
#include<cstdio> using namespace std; const int Maxn=100010; const int Maxm=500010; int dfn[Maxn],low[Maxn]; bool vis[Maxn]; long long ans[Maxn]; int ind; struct Edge{ int v,nxt; Edge(){} Edge(int a,int b){ v=a;nxt=b; } }; Edge e[Maxm*2]; int head[Maxn]; int nume; inline void addEdge(int a,int b){ e[++nume]=Edge(a,head[b]); head[b]=nume; e[++nume]=Edge(b,head[a]); head[a]=nume; } int n,m; int siz[Maxn]; inline int remin(int a,int b){ if (a<b) return a; return b; } void tarjan(int x){ long long tmpSiz=0; vis[x]=true; siz[x]=1; dfn[x]=low[x]=++ind; for (int i=head[x];i;i=e[i].nxt){ int v=e[i].v; if (!vis[v]){ tarjan(v); siz[x]+=siz[v]; low[x]=remin(low[x],low[v]); //割点 if (dfn[x]<=low[v]){ ans[x]+=tmpSiz*(long long)siz[v]; tmpSiz+=siz[v]; } }else{ low[x]=remin(low[x],dfn[v]); } } ans[x]+=tmpSiz*(long long)(n-tmpSiz-1); } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); addEdge(x,y); } for (int i=1;i<=n;i++) if (!vis[i]) tarjan(i); for (int i=1;i<=n;i++){ printf("%lld\n",(ans[i]+n-1)*2); } return 0; } |

原文链接:BZOJ1123: [POI2008]BLO
WNJXYKの博客 版权所有,转载请注明出处。
还没有任何评论,你来说两句吧!