算得上是比较水的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