bzoj2730: [HNOI2012]矿场搭建

容易看出是双联通。

and then??

割点!!终于有题证明了low[x]=min(low[x],dfn[y]);不能改成low[y]了

然后不会做(对强联通理解不够深刻)

先把每个联通块割点数弄出来,再找一次每个联通块

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;

struct node
{
    int x,y,next;
}a[1100];int len,last[510];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}

int z,low[510],dfn[510],cut[510];
void findcut(int x)
{
    dfn[x]=low[x]=++z;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(dfn[y]==0)
        {
            findcut(y);
            low[x]=min(low[x],low[y]);
            if(low[y]>=dfn[x])cut[x]++;
        }
        else low[x]=min(low[x],dfn[y]);
    }
}

int ans1;LL ans2;
int top,sta[510];
void findans(int x)
{
    dfn[x]=low[x]=++z;
    sta[++top]=x;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(dfn[y]==0)
        {
            findans(y);
            low[x]=min(low[x],low[y]);
            if(low[y]>=dfn[x])
            {
                int i;int cc=0,tot=0;
                do
                {
                    i=sta[top];top--;
                    if(cut[i]>=2)cc++;
                    tot++;
                }while(i!=y);
                i=x;
                if(cut[i]>=2)cc++;
                tot++;
                
                if(cc==0) ans1+=2, ans2*=tot*(tot-1)/2;
                if(cc==1) ans1++, ans2*=tot-1;
                
            }
        }
        else low[x]=min(low[x],dfn[y]);
    }
}

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int n,m,x,y,ttt=0;
    while(scanf("%d",&m)!=EOF)
    {
        if(m==0)break;ttt++;
        n=0;len=0;memset(last,0,sizeof(last));
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            ins(x,y);ins(y,x);
            n=max(n,max(x,y));
        }
        
        z=0;
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(cut,0,sizeof(cut));
        for(int i=1;i<=n;i++)
            if(dfn[i]==0)findcut(i);
            else cut[i]++;
        
        z=0;
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        ans1=0;ans2=1;
        for(int i=1;i<=n;i++)
            if(dfn[i]==0)findans(i);
        
        printf("Case %d: %d %lld\n",ttt,ans1,ans2);
    }
    return 0;
}

 

posted @ 2018-03-14 20:24  AKCqhzdy  阅读(182)  评论(0编辑  收藏  举报