算得上是比较水的E题了吧,自己想了想写了写居然1A了
对于这道题,我们很容易想到对于原图的一个边双,定向后任意两点间一定可达
那么我们可以求出原图的边双并将每个边双缩成一个点
那么原图就变成了无环的无向图,也就是一片森林
之后我们考虑每个任务:
1、如果S和T处于一个边双里,显然是可行的
2、如果S和T处于两棵树中,显然不连通不可行
3、S和T处于一棵树中,那么S->lca的所有边都是向上的,lca->T的所有边的都是向下的
对于第三种情况,我们可以在S上打一个up标记,在T上打一个down标记
之后在lca上将传递过来的up和down清除即可
那么最后我们只需要对森林做一遍DFS即可判断可行性
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<stack>
using namespace std;
const int maxn=200010;
int n,m,q;
int u,v;
struct Edge{
int u,v;
}c[maxn];
int h[maxn],cnt=1;
struct edge{
int to,next;
}G[maxn<<2];
int pre[maxn],low[maxn];
int dfs_clock=0,bcc_cnt=0;
int bccno[maxn],f[maxn];
int fa[maxn],anc[maxn][20];
int dep[maxn];
int up[maxn],down[maxn];
stack<int>S;
int ufs(int x){return f[x]==x?x:f[x]=ufs(f[x]);}
void add(int x,int y){++cnt;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;}
void DFS(int u,int f){
pre[u]=low[u]=++dfs_clock;S.push(u);
for(int i=h[u];i;i=G[i].next){
if(i==(f^1))continue;
int v=G[i].to;
if(!pre[v]){
DFS(v,i);
low[u]=min(low[u],low[v]);
}else if(!bccno[v])low[u]=min(low[u],pre[v]);
}
if(low[u]==pre[u]){
bcc_cnt++;
for(;;){
int now=S.top();S.pop();
bccno[now]=bcc_cnt;
if(now==u)break;
}
}return;
}
void Get_Tree(){
for(int i=1;i<=n;++i){
if(!pre[i])DFS(i,0);
}return;
}
void Get_DFS(int u,int f){
fa[u]=f;
for(int i=h[u];i;i=G[i].next){
int v=G[i].to;
if(v==f)continue;
dep[v]=dep[u]+1;
Get_DFS(v,u);
}return;
}
void pre_LCA(){
for(int i=1;i<=n;++i){
anc[i][0]=fa[i];
for(int j=1;(1<<j)<=n;++j)anc[i][j]=-1;
}
for(int j=1;(1<<j)<=n;++j){
for(int i=1;i<=n;++i){
if(anc[i][j-1]!=-1){
int a=anc[i][j-1];
anc[i][j]=anc[a][j-1];
}
}
}return;
}
int LCA(int p,int q){
if(dep[p]<dep[q])swap(p,q);
int log;
for(log=0;(1<<log)<=dep[p];++log);log--;
for(int i=log;i>=0;--i){
if(dep[p]-(1<<i)>=dep[q])p=anc[p][i];
}
if(p==q)return p;
for(int i=log;i>=0;--i){
if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i]){
p=anc[p][i];q=anc[q][i];
}
}return fa[p];
}
void check(int u,int f){
for(int i=h[u];i;i=G[i].next){
int v=G[i].to;
if(v==f)continue;
check(v,u);
up[u]+=up[v];down[u]+=down[v];
}
if(up[u]>0&&down[u]>0){
printf("No\n");
exit(0);
}return;
}
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;++i){
scanf("%d%d",&c[i].u,&c[i].v);
add(c[i].u,c[i].v);add(c[i].v,c[i].u);
}
Get_Tree();
memset(h,0,sizeof(h));cnt=1;
for(int i=1;i<=n;++i)f[i]=i;
for(int i=1;i<=m;++i){
int a=bccno[c[i].u];
int b=bccno[c[i].v];
if(a!=b){
add(a,b);add(b,a);
int d1=ufs(a),d2=ufs(b);
if(d1!=d2)f[d1]=d2;
}
}
for(int i=1;i<=bcc_cnt;++i){
int rt=ufs(i);
if(rt==i)Get_DFS(rt,-1);
}
pre_LCA();
for(int i=1;i<=q;++i){
scanf("%d%d",&u,&v);
int a=bccno[u],b=bccno[v];
if(ufs(a)!=ufs(b)){printf("No\n");return 0;}
int lca=LCA(a,b);
up[a]++;down[b]++;up[lca]--;down[lca]--;
}
for(int i=1;i<=bcc_cnt;++i){
int rt=ufs(i);
if(rt==i)check(rt,-1);
}printf("Yes\n");return 0;
}
原文:http://www.cnblogs.com/joyouth/p/5369181.html