bzoj1123 [POI2008]BLO——求割点子树相乘

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1123

思路倒是有的,不就是个乘法原理吗,可是不会写...代码能力...

写了一堆麻麻烦烦乱七八糟的东西写不下去了,去看TJ...

原来是在 tarjan 里面就顺便算出来了啊!真是精妙!这就是构建出了一个 dfs 搜索树了呢;

码力还需多多提升...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
int const maxn=1e5+5,maxm=5e5+5;
int n,m,hd[maxn],ct,siz[maxn],dfn[maxn],low[maxn],tim;
ll ans[maxn];
struct N{
    int to,nxt;
    N(int t=0,int n=0):to(t),nxt(n) {}
}ed[maxm<<1],edge[maxm<<1];
void add(int x,int y){ed[++ct]=N(y,hd[x]); hd[x]=ct;}
void tarjan(int x,int f)
{
    dfn[x]=low[x]=++tim; 
    ll t=0; siz[x]=1;//注意t是ll,否则下面算给ans时爆int 
    for(int i=hd[x],u;i;i=ed[i].nxt)
    {
        if((u=ed[i].to)==f)continue;
        if(!dfn[u])
        {
            tarjan(u,x); siz[x]+=siz[u];
            low[x]=min(low[x],low[u]);
            if(low[u]>=dfn[x])ans[x]+=siz[u]*t,t+=siz[u];//t是割点的子树大小 
        }
        else low[x]=min(low[x],dfn[u]);
    }
    ans[x]+=t*(n-t-1);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    tarjan(1,0);
    for(int i=1;i<=n;i++)printf("%lld\n",(ans[i]+n-1)*2);
    return 0;
}

 

posted @ 2018-07-10 21:12  Zinn  阅读(175)  评论(0编辑  收藏  举报