【挖坑记】JZOJ 4729 道路修建

题目大意

一个无向图,把它变成边双连通图,求出至少要加多少条边。
n<=100000,m<=500000
时间限制 1s
空间限制 256M

解题思路

比较裸的模型,先缩环成树,再求出叶子节点个数,根节点需要特判。

#include
#include
#include
#define maxn 100000+6
#define fr(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;

struct poi
{
    int x;
    poi *nex;
} *a[maxn],*b[maxn];
int i,n,m,x,y,z,tot,top,col,ans,d[maxn],fa[maxn],pos[maxn],dfn[maxn],low[maxn];
bool kan[maxn];
void link(int x,int y)
{
    poi *p=new poi;
    p->x=y;
    p->nex=a[x];
    a[x]=p;
    return;
}
void linkk(int x,int y)
{
    poi *p=new poi;
    p->x=y;
    p->nex=b[x];
    b[x]=p;
    return;
}
void tarjan(int x)
{
    poi *p=new poi;
    dfn[x]=low[x]=++tot;
    d[++top]=x;
    kan[x]=1;
    for(p=a[x];p;p=p->nex)
        if (!dfn[p->x])
        {
            fa[p->x]=x;
            tarjan(p->x);
            low[x]=min(low[x],low[p->x]);
        } else if (kan[p->x] && p->x!=fa[x])
            low[x]=min(low[x],dfn[p->x]);

    if (dfn[x]==low[x])
    {
        int t=0;
        ++col;
        while (d[top]!=x)
        {
            kan[d[top]]=0;
            pos[d[top]]=col;
            ++t,--top;
        }
        kan[d[top]]=0;
        pos[d[top]]=col;
        ++t,--top;
    }
    return;
}
void dfs(int x)
{
    int cai=0;
    kan[x]=1;
    poi *p=new poi;
    for(p=b[x];p;p=p->nex)
        if (p->x!=fa[x] && !kan[p->x])
        {
            cai++;
            fa[p->x]=x;
            dfs(p->x);
        }
    if (x!=1 && !cai || x==1 && cai==1) ans++;
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    fr(i,1,m)
    {
        scanf("%d%d",&x,&y);
        link(x,y),link(y,x);
    }
    tarjan(1);
    poi *p=new poi;
    fr(i,1,n)
    {
        for(p=a[i];p;p=p->nex)
            if (pos[p->x]!=pos[i])
            {
                linkk(pos[p->x],pos[i]);
                linkk(pos[i],pos[p->x]);
            }
    }
    memset(fa,0,sizeof(fa));
    memset(kan,0,sizeof(kan));
    dfs(1);
    if (ans&1) ans=ans/2+1;
    else ans/=2;
    printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(挖坑记,树)