[Codeforces Round #310 DIV1E (CF555E)] Case of Computer Network

题意

给出一个无向图,要求将每一条边变为单向的,并且满足给定的点对的连通性。

题解

首先找出边双连通分量,边双连通分量中的点对一定存在对边的取向使得分量中任意两点相互到达(看做一个或多个圆环套在一起)。
缩点,重新标号,构建新图,一定会得到一棵或多棵树。
下面描述的点都为重新标号后的点,且在同一棵树中。
对于每个连通性要求 uv ,设他们的最近公共祖先为 lca ,更特殊地, lcau,lcav
那么 ulca 上每个点 x (除lca)所代表的子树都有一个要求, x x的父亲的边方向为上。
同理 lcav 上每个点 y (除lca)所代表的子树都有一个要求, y y的父亲的边方向为下。
两种要求可以用 up[u],down[u] 存储,并 dfs 进行子树求和,为了消除对 lca 以上节点的影响,还要对 up[lca],down[lca] 修改,对于每组 uv up[u]++,down[v]++,up[lca]--,down[lca]--
最后遍历时如果某节点 up[u] down[u] ,同时非零,则表明 u 与父亲的边既需要向上,又需要向下,出现了冲突,答案为No lca=u lca=b 是退化情况,处理方法不变。

代码

/// by ztx
/// find DCC --> condense points --> dfs to judge
#include <cstdio>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
    if (CH == '-') NEG = true , CH = getchar() ;
    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
    if (NEG) ret = -ret ;
}

#define  maxn  200010LL
/// Edge
int e1[2][maxn<<1], e2[2][maxn<<1], star1[maxn] = {0}, star2[maxn] = {0}, tote1=1, tote2=1;
inline void AddEdge1(int u,int v)
{   tote1 ++ , e1[0][tote1] = v, e1[1][tote1] = star1[u], star1[u] = tote1;
    tote1 ++ , e1[0][tote1] = u, e1[1][tote1] = star1[v], star1[v] = tote1; }
inline void AddEdge2(int u,int v)
{   tote2 ++ , e2[0][tote2] = v, e2[1][tote2] = star2[u], star2[u] = tote2;
    tote2 ++ , e2[0][tote2] = u, e2[1][tote2] = star2[v], star2[v] = tote2; }
/// UnionFind
int par[maxn] = {0};
inline int GetAnc(int u) { return par[u] ? par[u] = GetAnc(par[u]) : u ; }
inline bool Union(int u,int v) { if (u = GetAnc(u), v = GetAnc(v), u == v) return false; par[u] = v; return true; }

int n, m, q;

#define  t(p)  e1[0][p]
#define  n(p)  e1[1][p]
#define  s(u)  star1[u]
/// world 1 begin
int sta[maxn], dfn[maxn], low[maxn], belong[maxn], top, idx, cntblc;
bool ins[maxn] = {false};

void dfs_Tarjan(int u,int back) {
    int v, p;
    dfn[u] = low[u] = ++idx, sta[++top] = u, ins[u] = true;
    for (p = s(u); v = t(p), p; p = n(p))
        if (p != back)
            if (!dfn[v]) {
                dfs_Tarjan(v,p^1);
                if (low[u] > low[v]) low[u] = low[v];
            } else if (ins[v] && low[u]>dfn[v]) low[u] = dfn[v];
    if (dfn[u] != low[u]) return;
    for (cntblc ++ , v = -1; u != v; )
        v = sta[top--], ins[v] = false, belong[v] = cntblc;
}

inline void world1() {
    int i, u, v;
    read(n), read(m), read(q);
    Rep (i,1,m)
        read(u), read(v), AddEdge1(u,v);
    top = idx = cntblc = 0;
    Rep (u,1,n)
        if (!dfn[u]) dfs_Tarjan(u,0);
}
/// world 1 end
inline void BuildNewWorld() {
    int u, v, p;
    Rep (u,1,n)
        for (p = s(u);v = t(p), p; p = n(p))
            if (belong[u] != belong[v])
                if (Union(belong[u],belong[v]))
                    AddEdge2(belong[u],belong[v]);
}

#undef   t
#undef   n
#undef   s
#define  t(p)  e2[0][p]
#define  n(p)  e2[1][p]
#define  s(u)  star2[u]
/// world 2 begin
int dep[maxn], fa[18][maxn] = {0}, up[maxn] = {0}, down[maxn] = {0};
bool YES;

inline int LCA(int u,int v) {
    int k;
    if (dep[u] < dep[v]) u ^= v ^= u ^= v;
    if (dep[u] > dep[v]) for (k = 17; ~k; k -- ) if (dep[fa[k][u]] >= dep[v]) u = fa[k][u];
    if (u == v) return u;
    for (k = 17; ~k; k -- ) if (fa[k][u] != fa[k][v]) u = fa[k][u], v = fa[k][v];
    return fa[0][u];
}

void dfs(int u,int d) {
    int v, p;
    dep[u] = d+1;
    for (p = 0; p < 17; p ++ ) if (!(fa[p+1][u]=fa[p][fa[p][u]])) break;
    for (p = s(u); v = t(p), p; p = n(p))
        if (!dep[v]) fa[0][v] = u, dfs(v,d+1);
}

void Judge(int u) {
    if (!YES) return ;
    int v, p;
    for (p = s(u); v = t(p), p; p = n(p))
        if (dep[v] > dep[u])
            if (Judge(v), !YES) return;
            else up[u] += up[v], down[u] += down[v];
    if (up[u] && down[u]) YES = false;
}

inline void world2() {
    int u, v, lca;
    Rep (u,1,cntblc) if (GetAnc(u) == u) dfs(u,0);
    YES = true;
    while (q --> 0) {
        read(u), read(v);
        u = belong[u], v = belong[v];
        if (u == v) continue;
        if (GetAnc(u) != GetAnc(v)) { YES = false; break; }
        lca = LCA(u,v);
        up[u] ++ , down[v] ++ , up[lca] -- , down[lca] -- ;
    }
    if (YES) Rep (u,1,cntblc) if (GetAnc(u)==u && (Judge(u), !YES)) break;
    printf("%s\n",YES?"Yes":"No");
}
/// world 2 end
#undef   t
#undef   n
#undef   s
int main() {
    world1(); /// input, build graph, get DCC s
    BuildNewWorld(); /// build new graph
    world2(); /// answer query
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值