cf555e

cf555e(缩点)

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

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

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

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

#include 
#include 
#include 
using namespace std;

typedef pair 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]]tim){ f[j][i]=f[j][i-1]; continue; }
            if (dep[f[j][i-1]]

转载于:https://www.cnblogs.com/MyNameIsPc/p/9574939.html

你可能感兴趣的:(cf555e)