codeforces #310 div1 E

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

  

posted @ 2016-04-08 18:04  _Vertical  阅读(274)  评论(0编辑  收藏  举报