bzoj 2730: [HNOI2012]矿场搭建【tarjan】

先tarjan找割点和点双连通份量,而后对一个点双,若是没有割点,那么须要创建两个出口(割掉一个另外一个备用);若是只有一个割点,出口能够设立在任意一个非割点的地方;若是有两个及以上个割点,就不用建出口(能够直接到达其余联通块)ios

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1005;
int n,m,h[N],cnt,cas,ans1,dfn[N],low[N],tot,bl[N],s[N],top;
long long ans2;
struct qwe
{
    int ne,to;
}e[N];
int read()
{
	int r=0,f=1;
	char p=getchar();
	while(p>'9'||p<'0')
	{
		if(p=='-')
			f=-1;
		p=getchar();
	}
	while(p>='0'&&p<='9')
	{
		r=r*10+p-48;
		p=getchar();
	}
	return r*f;
}
void add(int u,int v)
{
	cnt++;
    e[cnt].ne=h[u];
    e[cnt].to=v;
    h[u]=cnt;
}
void tarjan(int u)
{
    dfn[u]=low[u]=++tot;
    for(int i=h[u];i;i=e[i].ne)
    {
        if(dfn[e[i].to])
            low[u]=min(low[u],dfn[e[i].to]);
        else
        {
            tarjan(e[i].to);
            low[u]=min(low[u],low[e[i].to]);
            if(low[e[i].to]>=dfn[u])
                bl[u]++;
        }
    }
}
void tarjan2(int u)
{
    dfn[u]=low[u]=++tot;
    s[++top]=u;
    for(int i=h[u];i;i=e[i].ne)
    {
        if(dfn[e[i].to])
            low[u]=min(low[u],dfn[e[i].to]);
        else
        {
            tarjan2(e[i].to);
            low[u]=min(low[u],low[e[i].to]);
            if(low[e[i].to]>=dfn[u])
            {
                int t,temp=0,size=0;
                do
                {
                    t=s[top--];
                    if(bl[t]>=2)
                        ++temp;
                    ++size;
                }
				while(t!=e[i].to);
                t=u;
                if(bl[t]>=2)
                    ++temp;
                ++size;
                if(!temp)
                    ans1+=2,ans2*=size*(size-1)/2;
                else if(temp==1)
                    ans1++,ans2*=size-1;
            }
        }
    }
}
int main()
{
    while(1)
    {	
		m=read();
		if(!m)
			break;
        memset(h,0,sizeof(h));
        memset(dfn,0,sizeof(dfn));
        memset(bl,0,sizeof(bl));
        cnt=1;n=0;ans1=0;ans2=1;
        for(int i=1;i<=m;i++)
        {
            int x=read(),y=read();
            n=max(n,max(x,y));
            add(x,y),add(y,x);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i);
            else
                bl[i]++;
        memset(dfn,0,sizeof(dfn));
        for(int i=1;i<=n;i++)
            if(!dfn[i])								
                tarjan2(i);
		printf("Case %d: %d %lld\n",++cas,ans1,ans2);
    }
	return 0;
}