Case of Computer Network题解

Case of Computer Network题解

题意:
给定一个n个点,m条边的无向图。有q条有向路线分别从si到达ti。 现在你要给无向图的每条边分配一个方向。问是否存在一种分配答案使得所有路线都能够被满足。
\(1≤n,m,q≤2×10^5\)

这道题初看上去没什么思路,
但是我们仔细想想可以发现若一个点到另一个点有两条完全不同的路径的话,
我们可以让一条正向,一条反向,
无论怎样的询问都无妨。
哇!
”一个点到另一个点有两条完全不同的路径“?
这不是边双连通分量吗?
所有在同一个边双的询问就不用考虑了。
但是边双之间的路径呢?
怎么办?
同一个边双里没有什么作用,
我们干脆缩点,
之后就成了森林。
询问就剩两种情况:

1.不在同一颗树中,直接No;
2.在同一棵树中:看看每一条边是不是既要求正向,又要求反向。
这个树上差分搞一下就行了。
两个数组,
一个正向,一个反向。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+6;
int n,m,q;
int t1,t2,cnt=1,f[N],v[N],dfn[N],low[N],head[N],num2[N];
int deep=0,d[N],top[N],son[N],siz[N],book[N],num[N];
int f2[N],id[N],fa[N],head2[N],tot=0,cnt2=0,LCA;
map<int,int> ha[N];
struct edge{int nxt,to;}e[N<<1],g[N<<1];
inline int read(){
   int T=0,F=1; char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
   while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
   return F*T;
}
inline void add(int u,int v){e[++cnt].nxt=head[u],e[cnt].to=v,head[u]=cnt;}
inline void add2(int u,int v){g[++cnt2].nxt=head2[u],g[cnt2].to=v,head2[u]=cnt2;}
int getf(int x){return fa[x]==x?x:fa[x]=getf(fa[x]);}
void merge(int x,int y){
    x=getf(x),y=getf(y);
    if(x==y) return;
    fa[x]=y; 
}
void tarjan(int u,int fr){
    dfn[u]=low[u]=++deep;
    for(int i=head[u];i;i=e[i].nxt){
        if(i==fr) continue;
        if(!dfn[e[i].to]) f[e[i].to]=u,tarjan(e[i].to,i^1),low[u]=min(low[u],low[e[i].to]);
        else low[u]=min(low[u],dfn[e[i].to]);
    }
}
void dfs(int x,int ff,int o){
    f2[x]=ff,d[x]=d[ff]+1,siz[x]=1,id[x]=o; int maxt=0;
    for(int i=head2[x];i;i=g[i].nxt) if(g[i].to!=ff){dfs(g[i].to,x,o),siz[x]+=siz[e[i].to]; if(siz[maxt]<siz[g[i].to]) maxt=g[i].to;}
    son[x]=maxt;
}
void dfs2(int x,int topx){
    top[x]=topx;
    if(son[x]) dfs2(son[x],topx);
    for(int i=head2[x];i;i=g[i].nxt) if(g[i].to!=f2[x]&&g[i].to!=son[x]) dfs2(g[i].to,g[i].to);
}
void dfs3(int x){
     v[x]=1;
     for(int i=head2[x];i;i=g[i].nxt) if(g[i].to!=f2[x]) dfs3(g[i].to),num[x]+=num[g[i].to],num2[x]+=num2[g[i].to];
     if(num[x]&&num2[x]){printf("No\n"); exit(0);}
}
int lca(int x,int y){
   while(top[x]!=top[y]){
      if(d[top[x]]<d[top[y]]) swap(x,y);
      x=f2[top[x]];
   }
   if(d[x]>d[y]) swap(x,y);
   return x;
}
int main(){
   n=read(),m=read(),q=read();
   for(int i=1;i<=m;++i) t1=read(),t2=read(),add(t1,t2),add(t2,t1);
   for(int i=1;i<=n;++i){if(!dfn[i]) tarjan(i,0); fa[i]=i;}
   for(int i=1;i<=n;++i) if(f[i]&&low[i]>dfn[f[i]]) v[i]=1,ha[i][f[i]]=ha[f[i]][i]=1;
   for(int i=1;i<=n;++i) for(int j=head[i];j;j=e[j].nxt) if(ha[i].find(e[j].to)==ha[i].end()) merge(i,e[j].to);
   for(int i=1;i<=n;++i){
       t1=getf(i);
       if(!v[i]) continue;
       if(!book[fa[i]]) ++tot,book[fa[i]]=tot;
       if(!book[fa[f[i]]]) ++tot,book[fa[f[i]]]=tot;
       add2(book[fa[i]],book[fa[f[i]]]),add2(book[fa[f[i]]],book[fa[i]]);
   }
   for(int i=1;i<=tot;++i) if(!id[i]) dfs(i,0,i),dfs2(i,i);
   for(int i=1;i<=q;++i){
       t1=read(),t2=read(),t1=book[fa[t1]],t2=book[fa[t2]];
       if(id[t1]!=id[t2]){printf("No\n"); return 0;}
       if(t1==t2) continue;
       LCA=lca(t1,t2),++num[t1],--num[LCA],++num2[t2],--num2[LCA]; 
   }
   memset(v,0,sizeof(v));
   for(int i=1;i<=tot;++i) if(!v[i]) dfs3(i);
   printf("Yes\n");
   return 0;
}
posted @ 2019-11-03 15:08  lsoi_ljk123  阅读(292)  评论(0编辑  收藏  举报