zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    leetcode[68] Climbing Stairs
    leetcode[67] Plus One
    17_8_16 接口实例化的方法
    17_8_15 lambda 表达式
    17_8_14 回调函数
    17_8_11 Spring Jdbc+Dbcp
    17_8_10 eclipse 中复制网上代码 出现 报错 问题(0)
    17_8_10 PostgreSql Mac
    17_8_10 项目开发流程
    17_8_9 html 不常用的标签
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/9574939.html
Copyright © 2011-2022 走看看