[POI2008] BLO

link

试题分析

 分两种情况考虑。

当此点不是割点是,答案是$2 imes (n-1)$。

当是割点时,我们发现这个点把树分成了若干个联通块,只要两两相乘即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int N=100001;
const int M=500001;
struct node{
    int u,v,nex;
}x[M<<1];
int head[N],cnt,n,m,dfn[N],low[N],num;
void add(int u,int v){
    x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
int size[N],rt,ans[N];
void tarjan(int f,int fath){
    dfn[f]=low[f]=++num;size[f]=1;
    int flag=0,st=0,sum=0;
    for(int i=head[f];i!=-1;i=x[i].nex){
        if(x[i].v==fath) continue;
        if(!dfn[x[i].v]){
            flag++;
            tarjan(x[i].v,f);
            size[f]+=size[x[i].v];
            low[f]=min(low[f],low[x[i].v]);
            if((flag>1&&f==rt)||(dfn[f]<=low[x[i].v]&&f!=rt)){
                ans[f]+=(size[x[i].v])*(n-size[x[i].v]);
                sum+=size[x[i].v];
                st=1;
            }
        }else low[f]=min(low[f],dfn[x[i].v]);
    }
    if(!st) ans[f]=(n-1)*2;
    if(st) ans[f]+=(n-1+(n-sum-1)*(sum+1));
    return;
}
signed main(){
    memset(head,-1,sizeof(head));
    n=read(),m=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read();
        add(u,v),add(v,u);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i]) rt=i,tarjan(i,0);
    for(int i=1;i<=n;i++) printf("%lld
",ans[i]);
}
View Code
原文地址:https://www.cnblogs.com/si-rui-yang/p/10173350.html