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

题目描述

传送门

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

题解

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

代码

#include
#include
#include
#include
#include
#define N 1000003 
#define LL long long
using namespace std;
int n,m,tot,point[N],v[N],nxt[N],dfsn[N],belong[N],low[N],ins[N],st[N],top,cnt,sz,root;
LL ans[N],sum[N];
struct data{
    int point[N],nxt[N],v[N],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<
    }
    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,算法)