codeforces CF732F Tourist Reform Tarjan边双连通分量

$ \rightarrow $ 戳我进CF原题

  • 一张有向图中,设 $ r_i $ 为从点 $ i $ 出发能够到达的点的数量。
  • 定义有向图的“改良值”为 $ r_i $ 的最小值。
  • 现给出一张无向图,要求给每条边定一个方向,使产生的有向图“改良值”最大。
  • $ n,m \le 400000 $

  • 对于无向图的每个“边双连通分量”,一定存在一种定向方法,使其改良值等于其大小
  • 把无向图缩点后,以最大的 $ e-DCC $ 为零出度点(终点) $ BFS $ 定向
  • 每个 $ e-DCC $ 内部 $ DFS $ 定向

这个定向其实就是瞎定,原题spj会看最大的强连通分量大小而已,不必在意和答案不一样

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define maxn 400005
#define PP pair<int,int>
#define mp(a,b) make_pair(a,b)
#define fi first
#define se second
vector<PP>e[maxn];
stack<int>s;
int low[maxn],dfn[maxn],tim,mxsz,rt;
bool vis[maxn];
int scc,bel[maxn];
void tarjan(int u,int fa){
    low[u]=dfn[u]=++tim; s.push(u); vis[u]=1;
    for(int i=0;i<e[u].size();++i){
        int v=e[u][i].fi;
        if(v==fa) continue;
        if(!dfn[v]){
            tarjan(v,u);
            low[u]=min(low[v],low[u]);
        } else if(vis[v])
            low[u]=min(dfn[v],low[u]);
    }
    if(low[u]==dfn[u]){
        int sz=0,x=0; ++scc;
        do{
            ++sz;
            x=s.top(); s.pop(); vis[x]=0;
            bel[x]=scc;
        }while(low[x]!=dfn[x]);
        if(sz>mxsz){ mxsz=sz; rt=u; }
    }
}
int fu[maxn],fv[maxn];
void dfs(int u){
    dfn[u]=0;
    //使用dfn数组代替vis,省掉memset的时间
    for(int i=0;i<e[u].size();++i){
        int v=e[u][i].fi,id=e[u][i].se;
        if(dfn[v]){
            if(bel[v]!=bel[u]){ fu[id]=v; fv[id]=u; }
            //当两点不属于一个连通分量,让边从另一边拉过来
            else{ fu[id]=u; fv[id]=v; }
            //否则就是连通分量上的点,顺势从u到v
            dfs(v);
        } else {
            fu[id]=u; fv[id]=v;
            //这种情况就是连通分量的终点,依旧从u到v
        }
    }
}
int n,m;
int main(){
    scanf("%d %d",&n,&m);
    for(int u,v,i=1;i<=m;++i){
        scanf("%d %d",&u,&v);
        e[u].push_back(mp(v,i));
        e[v].push_back(mp(u,i));
    }
    tarjan(1,0);
    printf("%d\n",mxsz);
    //这里我直接dfs定向了
    dfs(rt);
    for(int i=1;i<=m;++i)
        printf("%d %d\n",fu[i],fv[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/PotremZ/p/9447461.html

时间: 2024-08-11 23:58:39

codeforces CF732F Tourist Reform Tarjan边双连通分量的相关文章

CF732F Tourist Reform(边双联通)

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

[bzoj3331] [BeiJing2013] 压力(tarjan 点双连通分量)

题干: 这世界上有N个网络设备,他们之间有M个双向的链接.这个世界是连通的.在一段时间里,有Q个数据包要从一个网络设备发送到另一个网络设备.一个网络设备承受的压力有多大呢?很显然,这取决于Q个数据包各自走的路径.不过,某些数据包无论走什么路径都不可避免的要通过某些网络设备.你要计算:对每个网络设备,必须通过(包括起点.终点)他的数据包有多少个? 对于40%的数据,N,M,Q≤2000 对于60%的数据,N,M,Q≤40000 对于100%的数据,N≤100000,M,Q≤200000 题解: 必

CodeForces 732F Tourist Reform

边双连通分量. 这题有一点构造的味道.一个有向图,经过强连通缩点之后会形成一个有向无环图. 如果将最大的强连通分量放在顶端,其余的强连通分量都直接或间接指向他,那么这样就构造出了符合要求的图. 接下来就是要去寻找强连通分量.对于一个无向图来说,每一个边-双联通分量都可以将每条边定向之后构造成一个强连通分量,$dfs$一遍即可. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #

poj3352 road construction tarjan求双连通分量

填坑--链接:http://poj.org/problem?id=3352 题意:求出图中再加上几条边会全部边双连通. 思路大概就是求出图中所有的双连通分量,然后像$SCC$一样缩点,缩完后每两个双连通分量再连边即可. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn

【BZOJ-1123】BLO Tarjan 点双连通分量

1123: [POI2008]BLO Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 970  Solved: 408[Submit][Status][Discuss] Description Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通. Input 输入n<=100000 m<=500000及m条边 Output 输出n个数,代表如果把第

codeforces 652E Pursuit For Artifacts 边双连通分量

题意:n个点,m条边的无向图,有的边上有标记,每条边只能走一次 给你一个起点,一个终点,询问是否能找到从起点到终点的路径,这条路径至少包含一条含有标记的边 分析:然后边双缩点 下面介绍一下边双的性质 1,删掉边双内任意一条边,不影响边双的连通性 2,任取边双内两个点u,v,对于边双里面的任意一条边,至少包含于一条u到v的路径 所以对于这个题,可以运用上述的第二个性质,对于在边双里的标记边,都是可以经过的 然后缩点以后,变成一棵树,然后从起点所在的边双开始遍历,找到到终点所在边双的路径,询问权值是

tarjan 边双连通分量 对点进行分组 每组点都在一个双连通分量里边

int dfn[N],low[N],id[N],s[N],p,num,t,son[N];//dfn记录dfs时间戳//low代表当前点到达的最小时间戳,id对点进行分组编号.num是时间戳//s临时存储数据的手工栈,p栈顶元素的位置,son记录儿子因为无向图记录边都是两个边 void tarjan(int pos){ dfn[pos]=low[pos]=++num; s[++p]=pos; for(edge *it=adj[pos];it;it=it->next){ if(!dfn[it->i

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

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

(转)Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)

本文转载自:http://hi.baidu.com/lydrainbowcat/item/f8a5ac223e092b52c28d591c 作者提示:在阅读本文之前,请确保您已经理解并掌握了基本的Tarjan算法,不会的请到http://hi.baidu.com/lydrainbowcat/blog/item/42a6862489c98820c89559f3.html阅读.   基本概念:   1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如