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\n",mx);
    memset(vis,0,sizeof vis);
    dfs(rt);
    for(int i=1;i<=m;i++)
    {
        if(e[i].f==1)printf("%d %d\n",e[i].u,e[i].v);
        else printf("%d %d\n",e[i].v,e[i].u);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/9279582.html

时间: 2024-08-30 04:15:24

CF732 F Tourist Reform——边双连通分量的相关文章

POJ 3352 Road Construction(边双连通分量,桥,tarjan)

题解转自http://blog.csdn.net/lyy289065406/article/details/6762370   文中部分思路或定义模糊,重写的红色部分为修改过的. 大致题意: 某个企业想把一个热带天堂岛变成旅游胜地,岛上有N个旅游景点,保证任意2个旅游景点之间有路径连通的(可间接连通).而为了给游客提供更方便的服务,该企业要求道路部门在某些道路增加一些设施. 道路部门每次只会选择一条道路施工,在该条道路施工完毕前,其他道路依然可以通行.然而有道路部门正在施工的道路,在施工完毕前是

POJ 3177 Redundant Paths (桥,边双连通分量,有重边)

题意:给一个无向图,问需要补多少条边才可以让整个图变成[边双连通图],即任意两个点对之间的一条路径全垮掉,这两个点对仍可以通过其他路径而互通. 思路:POJ 3352的升级版,听说这个图会给重边.先看3352的题解http://www.cnblogs.com/xcw0754/p/4619594.html. 其实与3352不同的就是重边出现了怎么办?假如出现的重边刚好是桥呢? 首先要知道,[割点]可以将两个[点双连通分量]隔开来,因为仅一个[点双连通分量]中肯定无割点,那么每两个点对都同时处于若干

codeforces CF732F Tourist Reform Tarjan边双连通分量

$ \rightarrow $ 戳我进CF原题 一张有向图中,设 $ r_i $ 为从点 $ i $ 出发能够到达的点的数量. 定义有向图的"改良值"为 $ r_i $ 的最小值. 现给出一张无向图,要求给每条边定一个方向,使产生的有向图"改良值"最大. $ n,m \le 400000 $ 对于无向图的每个"边双连通分量",一定存在一种定向方法,使其改良值等于其大小 把无向图缩点后,以最大的 $ e-DCC $ 为零出度点(终点) $ BFS

CF732F Tourist Reform(边双联通)

题意 在一张有向图中,设 ri 为从点 i 出发能够到达的点的数量. 定义有向图的"改良值"为 ri 的最小值. 现给出一张无向图,要求给每条边定一个方向,使产生的有向图"改良值"最大. 输出 最大改良值和边的方向. n,m≤400000 题解 对于无向图的每个"边双连通分量",一定存在一种定向方法,使其改良值等于其大小 把无向图缩点后,以最大的 e-DCC 为零出度点(终点) BFS 定向 每个 e-DCC 内部 DFS 定向 1 #inclu

Poj 3352 Road Construction &amp; Poj 3177 Redundant Paths(边双连通分量+缩点)

Road Construction Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9465   Accepted: 4699 Description It's almost summer time, and that means that it's almost summer construction time! This year, the good people who are in charge of the ro

POJ 3177 Redundant Paths(边双连通分量)

[题目链接] http://poj.org/problem?id=3177 [题目大意] 给出一张图,问增加几条边,使得整张图构成双连通分量 [题解] 首先我们对图进行双连通分量缩点, 那么问题就转化为给出一棵树,加边使得其成为边双连通分量的最小边数, 只要从叶节点连一条边到任意节点,那么就可以使得这个叶节点加入到双连通分量中, 那么优先叶节点和叶节点连接,所以其答案为(叶节点+1)/2 [代码] #include <cstdio> #include <algorithm> #in

POJ3177 Redundant Paths 双连通分量

Redundant Paths Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the herd are forced to cross near the Tree of Rotten Apples. The cows are now tired of

poj3177 &amp;&amp; poj3352 边双连通分量缩点

Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12676   Accepted: 5368 Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the

连通分量模板:tarjan: 求割点 &amp;&amp; 桥 &amp;&amp; 缩点 &amp;&amp; 强连通分量 &amp;&amp; 双连通分量 &amp;&amp; LCA(最近公共祖先)

PS:摘自一不知名的来自大神. 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合. 3.点连通度:最小割点集合中的顶点数. 4.割边(桥):删掉它之后,图必然会分裂为两个或两个以上的子图. 5.割边集合:如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合. 6.边连通度:一个图的边连通度的定义为,最