ARC143D Bridges

题目


i i i i + n i+n i+n 看作一个点,对所有 a i a_i ai b i b_i bi 连边,得到的图称为 G G G,则 G G G 的割边 ( a i , b i ) (a_i,b_i) (ai,bi) 在原图中 ( a i , b i + n ) (a_i,b_i+n) (ai,bi+n) ( a i + n , b i ) (a_i+n,b_i) (ai+n,bi) 也是割边(因为 a i a_i ai b i b_i bi 之间只有一条路径)。

直接给出结论:除了上面的割边外,存在一种构造方案,不存在其他的割边。下面将构造之。

考虑把点 1 ∼ n 1\sim n 1n 看作是入点,点 n + 1 ∼ 2 n n+1\sim 2n n+12n 看作是出点,即若 M i = 0 M_i=0 Mi=0,连 a i → b i a_i\to b_i aibi,否则连 b i → a i b_i\to a_i biai。我们考虑图 G G G 中组成边双的边,是否能确定方向,在现在的图中能组成强连通分量。在当前图上跑 dfs,对于返祖边,就向上连,否则向下连。这样一定能保证最优。

时间复杂度 O ( n + m ) O(n+m) O(n+m)

#include
using namespace std;
const int N=2e5+10;
int n,m,a[N],b[N],vis[N],vis1[N<<1];
int head[N],nxt[N<<1],to[N<<1],ans[N<<1],cnt=1;
void add(int u,int v)
{
    to[++cnt]=v;
    nxt[cnt]=head[u];
    head[u]=cnt;
}
void dfs(int u,int fa)
{
    if(vis[u]) return;
    vis[u]=1;
    for(int i=head[u];i;i=nxt[i]){
        if((i^1)==fa||vis1[i]) continue;
        vis1[i^1]=vis1[i]=1;
        ans[i]=1,ans[i^1]=0;
        dfs(to[i],i);
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++) cin>>a[i];
    for(int i=1;i<=m;i++) cin>>b[i],add(a[i],b[i]),add(b[i],a[i]);
    for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0);
    for(int i=1;i<=m;i++) cout<<ans[i<<1];
}

你可能感兴趣的:(图论)