cf555e

cf555e(缩点)

给一个 n 个点 m 条边的图,以及 q 对点 (s,t),让你给 m 条边定向。问是否存在一种方案,使每对点的 s 能走到 t。 \(n,m,q≤ 2×10^5\).

首先,在一个边双内,一定存在一种定向方案,使得边双内点两两可达。(考虑桥)

因此,可以直接把边双缩点。然后树上差分看看有没有冲突即可。

注意rmq-st求lca用的是欧拉序!

#include <cstdio>
#include <functional>
#include <algorithm>
using namespace std;

typedef pair<int, int> pi;
#define mp make_pair
const int maxn=2e5+5;
int n, m, q;

struct Edge{
	int fr, to, nxt;
}e1[maxn*2], e2[maxn*2];
int fir1[maxn], fir2[maxn], cnte1=1, cnte2=0;
void addedge(int x, int y, Edge *e, int *fir, int &cnte){
	Edge &ed=e[++cnte]; ed.fr=x;
	ed.to=y; ed.nxt=fir[x]; fir[x]=cnte; }

int tim, dfn[maxn], low[maxn], st[maxn], tl, cntgp, gp[maxn];
void tarjan(int u, int pe, Edge *e, int *fir){ int v;
	dfn[u]=low[u]=++tim; st[++tl]=u;
	for (int i=fir[u]; i; i=e[i].nxt){
		v=e[i].to; if (i==pe) continue; //对于求桥只能保存父边 
		if (dfn[v]){ low[u]=min(low[u], dfn[v]); continue; }
		tarjan(v, i^1, e, fir); low[u]=min(low[u], low[v]);
	}
	if (dfn[u]!=low[u]) return;
	++cntgp;
	while (dfn[st[tl]]!=low[st[tl]]) gp[st[tl--]]=cntgp;
	gp[st[tl--]]=cntgp;
}

int block[maxn], cntb, dep[maxn], ftim[maxn], f[maxn*2][19], rt[maxn];
void st_dfs(int u, int p, Edge *e, int *fir){ int v;
	block[u]=cntb; dep[u]=dep[p]+1; ftim[u]=++tim; f[tim][0]=u;
	for (int i=fir[u]; i; i=e[i].nxt){
		v=e[i].to; if (v==p) continue;
		st_dfs(v, u, e, fir); 
		f[++tim][0]=u;  //必须放在这里!!至于为什么,想想菊花(树) 
	}
}

int up[maxn], down[maxn];  //标记类型:立即生效,而不是处理后生效 

int getlca(int x, int y){  //注意如果x>y要swap 
	x=ftim[x]; y=ftim[y]; 
	if (x>y) swap(x, y); int c=-1;
	for (int l=y-x+1; l; l>>=1) ++c;
	if (dep[f[x][c]]<dep[f[y-(1<<c)+1][c]]) return f[x][c];
	else return f[y-(1<<c)+1][c];
}

bool ans=true;
pi dfs(int u, int p, Edge *e, int *fir){
	pi upi=mp(up[u], down[u]), tmp;
	for (int i=fir[u]; i; i=e[i].nxt){
		if (e[i].to==p) continue;
		tmp=dfs(e[i].to, u, e, fir);
		upi.first+=tmp.first; upi.second+=tmp.second;
	}
	if (upi.first&&upi.second) ans=false;
	return upi;
}

int main(){
	scanf("%d%d%d", &n, &m, &q); int x, y, lca;
	for (int i=1; i<=m; ++i){
		scanf("%d%d", &x, &y); 
		addedge(x, y, e1, fir1, cnte1); 
		addedge(y, x, e1, fir1, cnte1); }
	for (int i=1; i<=n; ++i) if (!dfn[i]) tarjan(i, 0, e1, fir1);
	int g1, g2; tim=0;
	for (int i=2; i<=cnte1; ++i)
		if ((g1=gp[e1[i].fr])!=(g2=gp[e1[i].to]))
			addedge(g1, g2, e2, fir2, cnte2);
	for (int i=1; i<=cntgp; ++i) 
		if (!dep[i]) ++cntb, rt[i]=1, st_dfs(i, 0, e2, fir2);
	for (int i=1; i<19; ++i)	
		for (int j=1; j<=tim; ++j){
			if (j+(1<<i-1)>tim){ f[j][i]=f[j][i-1]; continue; }
			if (dep[f[j][i-1]]<dep[f[j+(1<<i-1)][i-1]]) 
			f[j][i]=f[j][i-1]; else f[j][i]=f[j+(1<<i-1)][i-1];
		}
	for (int i=1; i<=q; ++i){
		scanf("%d%d", &x, &y); x=gp[x]; y=gp[y]; lca=getlca(x, y);
		if (block[x]!=block[y]){ puts("No"); return 0; }
		up[x]+=1; up[lca]+=-1; down[y]+=1; down[lca]+=-1;
	}
	for (int i=1; i<=cntgp; ++i) 
		if (rt[i]) dfs(i, 0, e2, fir2); 
	puts(ans?"Yes":"No");
	return 0;
}
posted @ 2018-09-02 19:42  pechpo  阅读(277)  评论(0编辑  收藏  举报