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;
}
posted @ 2020-05-02 22:11  HN-wrp  阅读(154)  评论(0编辑  收藏  举报