• 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
    ",ttt,ans1,ans2);
        }
        return 0;
    }
  • 相关阅读:
    怎么打jar包 jar怎么运行
    ORACLE directory 目录
    materialized view 和snapshot
    OS级别kill 进程
    ORA01843 not a valid month
    物化视图 Materialized View
    oracle数据字典
    在oracle中如何退出edit模式
    Oracle临时表
    Oracle 查看 对象 持有 锁 的情况 (添加了V$SQL视图,这样可以一起查出具体导致这种锁的SQL语句,一次性就搞定了)
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/8569856.html
Copyright © 2020-2023  润新知