题意
给出一个无向图,要求将每一条边变为单向的,并且满足给定的点对的连通性。
题解
首先找出边双连通分量,边双连通分量中的点对一定存在对边的取向使得分量中任意两点相互到达(看做一个或多个圆环套在一起)。
缩点,重新标号,构建新图,一定会得到一棵或多棵树。
下面描述的点都为重新标号后的点,且在同一棵树中。
对于每个连通性要求
u→v
,设他们的最近公共祖先为
lca
,更特殊地,
lca≠u,lca≠v
。
那么
u→lca
上每个点
x
(除
同理
lca→v
上每个点
y
(除
两种要求可以用
up[u],down[u]
存储,并
dfs
进行子树求和,为了消除对
lca
以上节点的影响,还要对
up[lca],down[lca]
修改,对于每组
u→v
,up[u]++,down[v]++,up[lca]--,down[lca]--
最后遍历时如果某节点
up[u]
与
down[u]
,同时非零,则表明
u
与父亲的边既需要向上,又需要向下,出现了冲突,答案为
代码
/// 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;
}