您的位置:首页 > 其它

bzoj 1123: [POI2008]BLO (tarjan求点双+树形DP)

2017-04-06 14:57 537 查看

题目描述

传送门

题目大意:给出一个无向连通图,求删去一个点后有多少点对不连通。

题解

tarjan求点双,然后对于点双新建节点,并连接所有点双中的节点,形成一棵树后进行树形DP即可。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define N 1000003
#define LL long long
using namespace std;
int n,m,tot,point
,v
,nxt
,dfsn
,belong
,low
,ins
,st
,top,cnt,sz,root;
LL ans
,sum
;
struct data{
int point
,nxt
,v
,tot;
void add(int x,int y){
tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
//  cout<<x<<" "<<y<<endl;
}
void dfs(int x,int fa){
if (x<=n) sum[x]=1;
for (int i=point[x];i;i=nxt[i]){
if (v[i]==fa) continue;
dfs(v[i],x);
ans[x]+=sum[x]*sum[v[i]];
sum[x]+=sum[v[i]];
}
LL t=(LL)n-sum[x];
ans[x]+=sum[x]*t;
}
}E;
void add(int x,int y)
{
tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void tarjan(int x)
{
dfsn[x]=low[x]=++sz; ins[x]=1; st[++top]=x;
for (int i=point[x];i;i=nxt[i]){
if (!dfsn[v[i]]) {
tarjan(v[i]); low[x]=min(low[x],low[v[i]]);
if (dfsn[x]<=low[v[i]]){
int j; cnt++;
while (1) {
j=st[top--];
E.add(cnt+n,j);
if (j==v[i]) break;
}
E.add(cnt+n,x);
}
}
else if (ins[v[i]]) low[x]=min(low[x],dfsn[v[i]]);
}
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++){
int x,y; scanf("%d%d",&x,&y);
add(x,y);
}
tarjan(1); root=1;
E.dfs(root,0);
for (int i=1;i<=n;i++) printf("%lld\n",ans[i]*2);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tarjan 树形DP