Luogu CF555E 【Case of Computer Network】
其实如果这是一颗树的话很好搞,把\(s\)到\(lca(s,t)\) 向上连,\(lca(s,t)\)到\(t\)向下连即可(然而事情并不是这样子的...)。
我们考虑什么样的情况是一定可行的呢?每两个点之间都有两条以上的路径,那就可以一边向前,一边向后,绝对可以。也就是求双联通分量以内是一定可以的,所以考虑缩点。惊奇的发现得到了一片森林(两点之间最多一条边,否则就被缩点了),那不就好搞了嘛!特判在不同树上的情况,直接在缩点的时候暴力搞定就行。在同一棵树上可以树剖/树上差分维护。最后一遍dfs判定标记是否重复就行了
那么现在问题就是怎没求双联通分量了...我并不会诶....(现场学习)
#include <cstdio>
#define R register
const int MAXN=2e5+10;
const int MAXM=MAXN<<1;
inline int read()
{
#define C getchar()
char a=C;int x=0,f=1;
for(;a>'9'||a<'0';a=C) if(a=='-') f=-1;
for(;a>='0'&&a<='9';a=C) x=x*10+a-'0';
return x*f;
#undef C
}
inline int min(int x,int y) { return x<y?x:y;}
int n,m,q;
struct edge
{
int fr,to,next;
}e1[MAXM];
struct Edge
{
int to,next;
}e2[MAXM];
int head1[MAXN],cnt1=1;
int head2[MAXN],cnt2=1;
inline void add1(int x,int y)
{
cnt1++;
e1[cnt1].fr=x;
e1[cnt1].to=y;
e1[cnt1].next=head1[x];
head1[x]=cnt1;
}
inline void add2(int x,int y)
{
cnt2++;
e2[cnt2].to=y;
e2[cnt2].next=head2[x];
head2[x]=cnt2;
}
int dfn[MAXN],low[MAXN];
int col[MAXN],num;
int st[MAXN],tp;
int vis[MAXN];
int tot;
int be[MAXN];
inline void tarjan(int x,int fr)
{
dfn[x]=low[x]=++num;
col[x]=col[0];
st[++tp]=x,vis[x]=1;
for(R int i=head1[x];i;i=e1[i].next)
{
if((i^1)==fr) continue;
int y=e1[i].to;
if(!dfn[y])
{
tarjan(y,i);
low[x]=min(low[x],low[y]);
}
else
if(vis[y]) low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x])
{
int y=0;tot++;
while(y!=x)
{
y=st[tp];tp--;
be[y]=tot;vis[y]=0;
}
}
}
int dep[MAXN],fa[MAXN],top[MAXN],siz[MAXN],son[MAXN];
inline void dfs1(int x,int fx)
{
dep[x]=dep[fx]+1;
fa[x]=fx;
siz[x]=1;
for(R int i=head2[x];i;i=e2[i].next)
{
int y=e2[i].to;
if(y==fx) continue;
dfs1(y,x);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]]) son[x]=y;
}
}
inline void dfs2(int x,int topx)
{
top[x]=topx;
if(son[x]) dfs2(son[x],topx);
for(R int i=head2[x];i;i=e2[i].next)
{
int y=e2[i].to;
if(y==fa[x]||y==son[x]) continue;
dfs2(y,y);
}
}
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;
}
int up[MAXN],down[MAXN];
int tag[MAXN];
inline void dfs3(int x)
{
tag[x]=1;
for(R int i=head2[x];i;i=e2[i].next)
{
int y=e2[i].to;
if(y==fa[x]) continue;
dfs3(y);
up[x]+=up[y];
down[x]+=down[y];
}
}
int main()
{
n=read();m=read();q=read();
for(R int i=1;i<=m;i++)
{
int x=read();int y=read();
add1(x,y);add1(y,x);
}
for(R int i=1;i<=n;i++)
if(!dfn[i])
{
col[0]++;
tarjan(i,0);
}
for(R int i=2;i<=cnt1;i+=2)
{
int x=e1[i].fr;
int y=e1[i].to;
if(be[x]==be[y]) continue;
add2(be[x],be[y]);
add2(be[y],be[x]);
}
for(R int i=1;i<=n;i++)
if(!dep[i])
{
dfs1(i,0);
dfs2(i,i);
}
for(R int i=1;i<=q;i++)
{
int x=read(),y=read();
if(col[x]!=col[y])
{
printf("No\n");return 0;
}
x=be[x],y=be[y];
int LCA=lca(x,y);
up[x]++;up[LCA]--;
down[y]++;down[LCA]--;
}
for(R int i=1;i<=n;i++)
if(!tag[i]) dfs3(i);
for(R int i=1;i<=n;i++)
if(up[i]&&down[i])
{
printf("No\n");
return 0;
}
printf("Yes\n");
return 0;
}