CF732 F Tourist Reform——边双连通分量

Posted zinn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF732 F Tourist Reform——边双连通分量相关的知识,希望对你有一定的参考价值。

题目:http://codeforces.com/contest/732/problem/F

首先把边双缩点,边双内部 dfs 一个顺序一定是可以从每个点走到边双内部所有点的,因为它是以环为基本单位;

然后对于缩点之后的图,找到 siz 最大的点作为根 dfs,再连反边,那么只有 siz 最大的那个点只能走到自己内部,就可以使答案最大;

结构体要开得精细一点,防止爆空间?还是什么奇奇怪怪的错误之类的...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const maxn=4e5+5;
int n,m,hd[maxn],ct=1,cnt=1,dfn[maxn],low[maxn],tim,col[maxn],cr,siz[maxn];
int sta[maxn],top,head[maxn];
bool vis[maxn];
//struct N{
//    int to,nxt,bh,u,v,f;
//    N(int t=0,int n=0,int b=0):to(t),nxt(n),bh(b) {}
//}ed[maxn<<1],e[maxn],edge[maxn<<1];//这样写会爆空间?! 
struct N{
    int to,nxt,bh;
    N(int t=0,int n=0,int b=0):to(t),nxt(n),bh(b) {}
}ed[maxn<<1],edge[maxn<<1];
struct E{int u,v,f;}e[maxn];
void add(int x,int y,int b){ed[++ct]=N(y,hd[x],b); hd[x]=ct;}
void add2(int x,int y,int b){edge[++cnt]=N(y,head[x],b); head[x]=cnt;}
void tarjan(int x,int f)
{
    dfn[x]=low[x]=++tim; vis[x]=1; sta[++top]=x; 
    for(int i=hd[x];i;i=ed[i].nxt)
    {
        int u=ed[i].to;
        if(u==f)continue;
        if(!dfn[u]) tarjan(u,x),low[x]=min(low[x],low[u]);
        else if(vis[u]) low[x]=min(low[x],dfn[u]);
    }
    if(dfn[x]==low[x])
    {
        cr++;
        while(sta[top]!=x)
        {
            int y=sta[top]; top--;
            vis[y]=0; col[y]=cr; siz[cr]++;
        }
        top--; vis[x]=0; col[x]=cr; siz[cr]++;
    }
}
void dfs(int x)
{
    vis[x]=1;
    for(int i=head[x],u,eg;i;i=edge[i].nxt)
    {
        if(vis[u=edge[i].to])continue;
        if(x==col[e[eg=edge[i].bh].u]) e[eg].f=0;
        else e[eg].f=1;
        dfs(u);
    }
}
void dfs2(int x)
{
    vis[x]=1;
    for(int i=hd[x],u,eg;i;i=ed[i].nxt)
    {
        u=ed[i].to;
        if(col[u]!=col[x])continue;
        if(x==e[eg=ed[i].bh].u) e[eg].f=1;
        else e[eg].f=0;
        if(!vis[u])dfs2(u);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&e[i].u,&e[i].v);
        add(e[i].u,e[i].v,i); add(e[i].v,e[i].u,i);
    }
    for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i,0);
    memset(vis,0,sizeof vis);
    for(int i=1;i<=n;i++) if(!vis[i])dfs2(i);
    for(int i=1,u,v;i<=ct;i++)
        if((u=col[ed[i].to])!=(v=col[ed[i^1].to]))add2(u,v,ed[i].bh),add2(v,u,ed[i].bh);
    int rt=0,mx=0;
    for(int i=1;i<=cr;i++)
        if(siz[i]>mx)mx=siz[i],rt=i;
    printf("%d
",mx);
    memset(vis,0,sizeof vis);
    dfs(rt);
    for(int i=1;i<=m;i++)
    {
        if(e[i].f==1)printf("%d %d
",e[i].u,e[i].v);
        else printf("%d %d
",e[i].v,e[i].u);
    }
    return 0;
}

 

以上是关于CF732 F Tourist Reform——边双连通分量的主要内容,如果未能解决你的问题,请参考以下文章

codeforces CF732F Tourist Reform Tarjan边双连通分量

CF 732F Tourist Reform——v-SCC+dfs

CodeForces 732F Tourist Reform

Codeforces Round #377 (Div. 2)F - Tourist Reform

CF659ENew Reform

cf246 ENew Reform (并查集找环)