BZOJ 1123 [POI2008]BLO(Tarjan算法)
【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=1123
【题目大意】
Byteotia城市有n个towns,m条双向roads. 每条road连接两个不同的towns,
没有重复的road. 所有towns连通。输出n个数,代表如果把第i个点去掉,将有多少对点不能互通。
【题解】
Tarjan算法的基础应用,如果x是y分支的割点,那么y就参与x点的答案贡献计数,
将割点为x的不同分支的size进行动态乘即可。
【代码】
#include <cstdio> #include <algorithm> #include <cstring> #include <vector> using namespace std; typedef long long LL; const int N=100010,M=500010; int n,m,g[N],v[M<<1],nxt[M<<1],ed; int dfn[N],low[N],num; LL ans[N],size[N]; void add_edge(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} void tarjan(int x){ dfn[x]=low[x]=++num; size[x]=1; LL tmp=0; for(int i=g[x];i;i=nxt[i])if(!dfn[v[i]]){ int y=v[i]; tarjan(y); size[x]+=size[y]; if(low[x]>low[y])low[x]=low[y]; if(dfn[x]<=low[y]){//x是割点 ans[x]+=tmp*size[y]; tmp+=size[y]; } }else if(low[x]>dfn[v[i]])low[x]=dfn[v[i]]; ans[x]+=tmp*(n-tmp-1); } void init(){ed=0;memset(g,0,sizeof(g));} int main(){ while(~scanf("%d%d",&n,&m)){ init(); memset(ans,0,sizeof(ans)); while(m--){ int x,y; scanf("%d%d",&x,&y); add_edge(x,y); add_edge(y,x); }tarjan(1); for(int i=1;i<=n;i++)printf("%lld\n",(ans[i]+n-1)<<1); }return 0; }
愿你出走半生,归来仍是少年