constint MAX_DEP =20;// 注意0,1點的邊界問題struct DominatorTree {int deg[N];// 入度int dep[N];//int dfn[N];int st[N];int tot;// 拓撲序, 要保證root是入度為0voidbfs(Graph &gh,int root){queue<int> q;q.push(root);tot =0;while(!q.empty()){int u = q.front();q.pop();dfn[u]=++tot;st[tot]= u;forg(i, gh.head[u], gh.eg){int v = gh.eg[i].e;if((--deg[v])==0){q.push(v);}}}}// 倍增2^k的父親int fa[N][MAX_DEP];// 倍增LCAintlca(int u,int v){if(dep[u]> dep[v]){swap(u, v);}int hu = dep[u], hv = dep[v];int tu = u, tv = v;for(int det = hv - hu, i =0; det; det >>=1, i++){if(det &1)tv = fa[tv][i];}if(tu == tv){return tu;}for(int i = MAX_DEP -1; i >=0; i--){if(fa[tu][i]== fa[tv][i]){continue;}tu = fa[tu][i];tv = fa[tv][i];}return fa[tu][0];}// 動態更新節點的父親屬性voidlineFa(int u,int v){fa[u][0]= v;for(int i =1; i < MAX_DEP; i++){v = fa[u][i]= fa[v][i -1];}}// 建樹, op是gh的反向圖,用來尋找其父親voidbuild(Graph &gh, Graph &op,int n,int root){memcpy(deg, gh.deg,sizeof(int)*(n +1));bfs(gh, root);for(int k =1; k <= tot; k++){int u = st[k], fath =-1;dep[u]=0;for(int i = op.head[u];~i; i = op.eg[i].nxt){int v = op.eg[i].e;if(dfn[v]> dfn[u])continue;fath =(fath ==-1? v :lca(fath, v));}if(fath ==-1) fath = u;lineFa(u, fath);dep[u]= dep[fath]+1;}}} dtree;
有向圖
Lengauer-Tarjan算法(待學)
例題
再貼一個被折磨了4天的那道題(順便學了下倍增LCA),HDU杭電2019暑期多校第三場B題 一個DAG圖下每次詢問給出的兩個點u,v到所有出度為0的點的支配點個數 這題通過反向建邊+虛點連接所有出度為0的點建立支配樹,每次查詢的時候,查詢樹上的u,v兩點的深度,容斥減去其LCA點的深度,就是其支配點的個數 HDU 6604 Blow up the city
// 巨菜的ACMer-Happy233#include<bits/stdc++.h>usingnamespace std;//-----typedefdouble db;typedeflonglong ll;typedefunsignedint ui;typedef vector<int> vi;typedef pair<int,int> pii;typedef pair<ll, ll> pll;#define mp make_pair#define fi first#define se second#define pw(x) (1ll << (x))#define bt(x, i) ((x >> i) & 1)#define sz(x) ((int)(x).size())#define all(x) (x).begin(),(x).end()#define rep(i, l, r) for(int i=(l);i<(r);++i)#define per(i, l, r) for(int i=(r)-1;i>=(l);--i)#define sf(x) scanf("%d", &(x))#ifndef ACM_LOCAL#define endl '\n'#endifconstdouble pi =acos(-1);constint MOD =int(998244353);#define forg(i, h, eg) for(int i = (h); ~i; i = (eg[i]).nxt)struct Edge {int e, nxt;ll v;Edge()=default;Edge(int a, ll b,int c =0):e(a),v(b),nxt(c){}booloperator<(const Edge &a)const{return(a.v == v ? e < a.e : v < a.v);}};const ll INF =ll(1e11);constint N =int(1e5+10);constint M =int(3e5+10);struct Graph {Edge eg[M];int deg[N];int head[N];int cnt;voidinit(int n){memset(head,-1,sizeof(int)*++n);memset(deg,0,sizeof(int)* n);cnt =0;}inlinevoidaddEdge(int x,int y, ll v =0){eg[cnt]=Edge(y, v, head[x]);head[x]= cnt++;deg[y]++;}};constint MAX_DEP =20;struct DominatorTree {int deg[N];// 入度int dep[N];//int dfn[N];int st[N];int tot;// 拓撲序, 要保證root是入度為0voidbfs(Graph &gh,int root){queue<int> q;q.push(root);tot =0;while(!q.empty()){int u = q.front();q.pop();dfn[u]=++tot;st[tot]= u;forg(i, gh.head[u], gh.eg){int v = gh.eg[i].e;if((--deg[v])==0){q.push(v);}}}}// 倍增2^k的父親int fa[N][MAX_DEP];// 倍增LCAintlca(int u,int v){if(dep[u]> dep[v]){swap(u, v);}int hu = dep[u], hv = dep[v];int tu = u, tv = v;for(int det = hv - hu, i =0; det; det >>=1, i++){if(det &1)tv = fa[tv][i];}if(tu == tv){return tu;}for(int i = MAX_DEP -1; i >=0; i--){if(fa[tu][i]== fa[tv][i]){continue;}tu = fa[tu][i];tv = fa[tv][i];}return fa[tu][0];}voidlineFa(int u,int v){fa[u][0]= v;for(int i =1; i < MAX_DEP; i++){v = fa[u][i]= fa[v][i -1];}}voidbuild(Graph &gh, Graph &op,int n,int root){memcpy(deg, gh.deg,sizeof(int)*(n +1));bfs(gh, root);for(int k =1; k <= tot; k++){int u = st[k], fath =-1;dep[u]=0;for(int i = op.head[u];~i; i = op.eg[i].nxt){int v = op.eg[i].e;if(dfn[v]> dfn[u])continue;fath =(fath ==-1? v :lca(fath, v));}if(fath ==-1) fath = u;lineFa(u, fath);dep[u]= dep[fath]+1;}}} dtree;Graph gh, op;voidsolve(){int n, m;while(cin >> n >> m){gh.init(n);op.init(n);rep(i,0, m){int a, b;cin >> a >> b;gh.addEdge(b, a);op.addEdge(a, b);}for(int i =1; i <= n; i++){if(gh.deg[i]==0){gh.addEdge(0, i);op.addEdge(i,0);}}dtree.build(gh, op, n,0);int q;cin >> q;while(q--){int u, v;cin >> u >> v;int f = dtree.lca(u, v);int ans = dtree.dep[u]+ dtree.dep[v]- dtree.dep[f]-1;cout << ans << endl;}}}intmain(){#ifdef ACM_LOCALfreopen("./data/1.in","r",stdin);// freopen("./data/std.out", "w", stdout);#elseios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);#endif#ifdef ACM_LOCALauto start =clock();#endifint t;cin >> t;while(t--)solve();#ifdef ACM_LOCALauto end =clock();cerr <<"Run Time: "<<double(end - start)/ CLOCKS_PER_SEC <<"s"<< endl;#endifreturn0;}