【Codeforces 555E】Case of Computer Network

边双缩点,树上差分

题目大意:

给定一张无向图,有 $q$ 条有向路径。

要求给无向图的每条边定向,并使 $q$ 条路径仍然连通。

问是否存在方案。

题解:

一个边双中的点,两两之间有至少两条路径,必然可达。所以先缩成一个点。

然后就变成一个森林上的问题了。

如果两个点不连通,那么显然不存在。

否则,我们拆成 $u\rightarrow \mathrm{LCA}(u,v)$ 和 $\mathrm{LCA}(u,v)\rightarrow v$ 两条路径。分别在这两条路径上打向上、向下的标记。

如果一条边既有向上有有向下则不可行。不存在则可以。

本题是最后查询,所以可以树上差分得到每条边,向上的链的数量和向下的链的数量。

Code:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<vector>
using namespace std;
const int N=2e5+5;
int n,m,q,X[N],Y[N],head[N],cnt=1,dfn[N],low[N],idx,sta[N],tp,SCC,bel[N],dep[N],fa[N],top[N],sz[N],son[N];
int siz[N],dad[N];
bool vis[N];
inline int find(int x){while(x!=dad[x])x=dad[x]=dad[dad[x]];return x;}
inline void merge(int u,int v){
    u=find(u),v=find(v);
    if(u==v)return;
    if(siz[u]<siz[v])swap(u,v);
    siz[u]+=siz[v],dad[v]=u;
}
struct edge{
    int to,nxt;
}e[N<<1];
vector<int>G[N];
void DFS(int now,int pre){
    dfn[now]=low[now]=++idx;
    vis[now]=1;
    sta[++tp]=now;
    for(int i=head[now];i;i=e[i].nxt)
    if(i!=pre){
        if(!dfn[e[i].to]){
            DFS(e[i].to,i^1);
            low[now]=min(low[now],low[e[i].to]);
        }else
        if(vis[now])low[now]=min(low[now],dfn[e[i].to]);
    }
    if(low[now]==dfn[now]){
        int v;
        ++SCC;
        do{
            v=sta[tp--];
            bel[v]=SCC;
            vis[v]=0;
        }while(v!=now);
    }
}
void dfs(int now){
    sz[now]=1;
    for(int to:G[now])if(!dep[to]){
        dep[to]=dep[now]+1,fa[to]=now;
        dfs(to);
        sz[now]+=sz[to];
        if(sz[son[now]]<sz[to])son[now]=to;
    }
}
void dfs2(int now){
    if(son[now])top[son[now]]=top[now],dfs2(son[now]);
    for(int to:G[now])
    if(dep[to]>dep[now]&&to!=son[now])dfs2(top[to]=to);
}
inline int LCA(int x,int y){
    while(top[x]!=top[y])
    if(dep[top[x]]>dep[top[y]])x=fa[top[x]];else y=fa[top[y]];
    return dep[x]<dep[y]?x:y;
}
void DfS(int now){
    for(int to:G[now])if(dep[to]>dep[now]){
        DfS(to);
        X[now]+=X[to],Y[now]+=Y[to];
    }
    if(X[now]&&Y[now])cout<<"No\n",exit(0);
}
int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>m>>q;
    for(int i=1;i<=n;++i)dad[i]=i;
    for(int i=1;i<=m;++i){
        int u,v;
        cin>>u>>v;
        e[++cnt]=(edge){v,head[u]},head[u]=cnt;
        e[++cnt]=(edge){u,head[v]},head[v]=cnt;
        merge(u,v);
    }
    for(int i=1;i<=n;++i)if(!dfn[i])DFS(i,0);
    for(int u=1;u<=n;++u)
    for(int i=head[u];i;i=e[i].nxt)
    if(bel[u]!=bel[e[i].to])
    G[bel[u]].push_back(bel[e[i].to]);
    for(int i=1;i<=SCC;++i)if(!dep[i])dep[i]=1,dfs(i),dfs2(i);
    while(q--){
        int u,v;
        cin>>u>>v;
        if(find(u)!=find(v))cout<<"No\n",exit(0);
        u=bel[u],v=bel[v];
        int w=LCA(u,v);
        ++X[u],++Y[v],--X[w],--Y[w];
    }
    for(int i=1;i<=SCC;++i)if(dep[i]==1)DfS(i);
    cout<<"Yes\n";
    return 0;
}