1.DAG
按照拓?fù)湫驈男〉酱筇幚?#xff0c;對于每個(gè)節(jié)點(diǎn),將所有連接它的點(diǎn)的lca求出來,它在支配樹上的父親就是這個(gè)lca。
2.一般圖
模板:
vector<int> g[N], rg[N], tg[N], G[N];
int in[N], dfn[N], rak[N], fa[N], sdom[N], idom[N], val[N], ufs[N], cnt;
LL sz[N];
void dfs1(int u) {sdom[u] = dfn[u] = ++cnt;rak[cnt] = u;for (int v : g[u]) {if(!dfn[v]) {fa[v] = u;dfs1(v);}}
}
void dfs2(int u) {sz[u] = 1;for (int v : G[u]) {dfs2(v);sz[u] += sz[v];}
}
int Find(int x) {if(ufs[x] == x) return x;int fx = Find(ufs[x]);if(sdom[val[ufs[x]]] < sdom[val[x]]) val[x] = val[ufs[x]];return ufs[x] = fx;
}
void lengauer_tarjan(int n) {///初始化cnt = 0;for (int i = 0; i <= n; ++i) {sz[i] = dfn[i] = in[i] = 0;ufs[i] = val[i] = i;g[i].clear(); ///原圖rg[i].clear();///反圖tg[i].clear();G[i].clear();}///輸入///從n出發(fā)g[0].pb(n), rg[n].pb(0);///從入度為0的出發(fā)for (int i = 1; i <= n; ++i) if(!in[i]) g[0].pb(i), rg[i].pb(0);dfs1(0);for (int i = cnt; i >= 2; --i) {int u = rak[i];for (int v : rg[u]) {if(!dfn[v]) continue;Find(v);sdom[u] = min(sdom[u], sdom[val[v]]);}ufs[u] = fa[u];tg[rak[sdom[u]]].pb(u);for (int v : tg[fa[u]]) {Find(v);if(sdom[val[v]] == sdom[v]) idom[v] = rak[sdom[v]];else idom[v] = val[v];}tg[fa[u]].clear();}for (int i = 1; i <= cnt; ++i) {int u = rak[i];if(idom[u] != rak[sdom[u]]) idom[u] = idom[idom[u]];}for (int i = 1; i <= n; ++i) if(dfn[i]) G[idom[i]].pb(i);dfs2(0);for (int i = 1; i <= n; ++i) printf("%d%c", dfn[i]?sz[i]:0, " \n"[i==n]);
}
例題1:P2597 [ZJOI2012]災(zāi)難
代碼:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb emplace_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//headconst int N = 1e5 + 5;
vector<int> g[N], rg[N], tg[N], G[N];
int in[N], dfn[N], rak[N], fa[N], sdom[N], idom[N], val[N], ufs[N], sz[N], cnt;
void dfs1(int u) {sdom[u] = dfn[u] = ++cnt;rak[cnt] = u;for (int v : g[u]) {if(!dfn[v]) {fa[v] = u;dfs1(v);}}
}
void dfs2(int u) {sz[u] = 1;for (int v : G[u]) {dfs2(v);sz[u] += sz[v];}
}
int Find(int x) {if(ufs[x] == x) return x;int fx = Find(ufs[x]);if(sdom[val[ufs[x]]] < sdom[val[x]]) val[x] = val[ufs[x]];return ufs[x] = fx;
}
void lengauer_tarjan(int n) {///初始化cnt = 0;for (int i = 0; i <= n; ++i) {dfn[i] = in[i] = 0;ufs[i] = val[i] = i;g[i].clear();rg[i].clear();tg[i].clear();G[i].clear();}///輸入for (int i = 1; i <= n; ++i) {int x;while(~scanf("%d", &x) && x) {g[x].pb(i);in[i]++;rg[i].pb(x);}}///輸入for (int i = 1; i <= n; ++i) if(!in[i]) g[0].pb(i), rg[i].pb(0);dfs1(0);for (int i = n+1; i >= 2; --i) {int u = rak[i];for (int v : rg[u]) {Find(v);sdom[u] = min(sdom[u], sdom[val[v]]);}ufs[u] = fa[u];tg[rak[sdom[u]]].pb(u);for (int v : tg[fa[u]]) {Find(v);if(sdom[val[v]] == sdom[v]) idom[v] = rak[sdom[v]];else idom[v] = val[v];}tg[fa[u]].clear();}for (int i = 1; i <= n+1; ++i) {int u = rak[i];if(idom[u] != rak[sdom[u]]) idom[u] = idom[idom[u]];}for (int i = 1; i <= n; ++i) G[idom[i]].pb(i);dfs2(0);for (int i = 1; i <= n; ++i) printf("%d\n", sz[i]-1);
}
int n;
int main() {scanf("%d", &n);lengauer_tarjan(n);return 0;
}
例題2:P5180 【模板】支配樹
代碼:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb emplace_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//headconst int N = 2e5 + 5;
vector<int> g[N], rg[N], tg[N], G[N];
int in[N], dfn[N], rak[N], fa[N], sdom[N], idom[N], val[N], ufs[N], sz[N], cnt;
void dfs1(int u) {sdom[u] = dfn[u] = ++cnt;rak[cnt] = u;for (int v : g[u]) {if(!dfn[v]) {fa[v] = u;dfs1(v);}}
}
void dfs2(int u) {sz[u] = 1;for (int v : G[u]) {dfs2(v);sz[u] += sz[v];}
}
int Find(int x) {if(ufs[x] == x) return x;int fx = Find(ufs[x]);if(sdom[val[ufs[x]]] < sdom[val[x]]) val[x] = val[ufs[x]];return ufs[x] = fx;
}
void lengauer_tarjan(int n) {///初始化cnt = 0;for (int i = 0; i <= n; ++i) {dfn[i] = in[i] = 0;ufs[i] = val[i] = i;g[i].clear();rg[i].clear();tg[i].clear();G[i].clear();}///輸入int m, u, v;scanf("%d", &m);for (int i = 1; i <= m; ++i) {scanf("%d %d", &u, &v);g[u].pb(v);in[v]++;rg[v].pb(u);}///輸入g[0].pb(1), rg[1].pb(0);dfs1(0);for (int i = n+1; i >= 2; --i) {int u = rak[i];for (int v : rg[u]) {Find(v);sdom[u] = min(sdom[u], sdom[val[v]]);}ufs[u] = fa[u];tg[rak[sdom[u]]].pb(u);for (int v : tg[fa[u]]) {Find(v);if(sdom[val[v]] == sdom[v]) idom[v] = rak[sdom[v]];else idom[v] = val[v];}tg[fa[u]].clear();}for (int i = 1; i <= n+1; ++i) {int u = rak[i];if(idom[u] != rak[sdom[u]]) idom[u] = idom[idom[u]];}for (int i = 1; i <= n; ++i) G[idom[i]].pb(i);dfs2(0);for (int i = 1; i <= n; ++i) printf("%d%c", sz[i], " \n"[i==n]);
}
int n;
int main() {scanf("%d", &n);lengauer_tarjan(n);return 0;
}
例題3:HDU 4694
代碼:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb emplace_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//headconst int N = 5e4 + 5;
vector<int> g[N], rg[N], tg[N], G[N];
int in[N], dfn[N], rak[N], fa[N], sdom[N], idom[N], val[N], ufs[N], cnt;
LL sz[N];
void dfs1(int u) {sdom[u] = dfn[u] = ++cnt;rak[cnt] = u;for (int v : g[u]) {if(!dfn[v]) {fa[v] = u;dfs1(v);}}
}
void dfs2(int u, LL d) {sz[u] = d;for (int v : G[u]) {dfs2(v, d+v);}
}
int Find(int x) {if(ufs[x] == x) return x;int fx = Find(ufs[x]);if(sdom[val[ufs[x]]] < sdom[val[x]]) val[x] = val[ufs[x]];return ufs[x] = fx;
}
void lengauer_tarjan(int n) {///初始化cnt = 0;for (int i = 0; i <= n; ++i) {sz[i] = dfn[i] = in[i] = 0;ufs[i] = val[i] = i;g[i].clear();rg[i].clear();tg[i].clear();G[i].clear();}///輸入int m, u, v;scanf("%d", &m);for (int i = 1; i <= m; ++i) {scanf("%d %d", &u, &v);g[u].pb(v);in[v]++;rg[v].pb(u);}///輸入g[0].pb(n), rg[n].pb(0);dfs1(0);for (int i = cnt; i >= 2; --i) {int u = rak[i];for (int v : rg[u]) {if(!dfn[v]) continue;Find(v);sdom[u] = min(sdom[u], sdom[val[v]]);}ufs[u] = fa[u];tg[rak[sdom[u]]].pb(u);for (int v : tg[fa[u]]) {Find(v);if(sdom[val[v]] == sdom[v]) idom[v] = rak[sdom[v]];else idom[v] = val[v];}tg[fa[u]].clear();}for (int i = 1; i <= cnt; ++i) {int u = rak[i];if(idom[u] != rak[sdom[u]]) idom[u] = idom[idom[u]];}for (int i = 1; i <= n; ++i) if(dfn[i]) G[idom[i]].pb(i);dfs2(0, 0);for (int i = 1; i <= n; ++i) printf("%lld%c", dfn[i]?sz[i]:0, " \n"[i==n]);
}
int n;
int main() {while(~scanf("%d", &n)) lengauer_tarjan(n);return 0;
}
例題4:Codechef Counting on a directed graph
代碼:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb emplace_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//headconst int N = 1e5 + 5;
vector<int> g[N], rg[N], tg[N], G[N];
int in[N], dfn[N], rak[N], fa[N], sdom[N], idom[N], val[N], ufs[N], cnt;
LL sz[N];
void dfs1(int u) {sdom[u] = dfn[u] = ++cnt;rak[cnt] = u;for (int v : g[u]) {if(!dfn[v]) {fa[v] = u;dfs1(v);}}
}
void dfs2(int u) {sz[u] = 1;for (int v : G[u]) {dfs2(v);sz[u] += sz[v];}
}
int Find(int x) {if(ufs[x] == x) return x;int fx = Find(ufs[x]);if(sdom[val[ufs[x]]] < sdom[val[x]]) val[x] = val[ufs[x]];return ufs[x] = fx;
}
void lengauer_tarjan(int n) {///初始化cnt = 0;for (int i = 0; i <= n; ++i) {sz[i] = dfn[i] = in[i] = 0;ufs[i] = val[i] = i;g[i].clear(); ///原圖rg[i].clear();///反圖tg[i].clear();G[i].clear();}///輸入int m, u, v;scanf("%d", &m);for (int i = 1; i <= m; ++i) {scanf("%d %d", &u, &v);g[u].pb(v);in[v]++;rg[v].pb(u);}///從n出發(fā)g[0].pb(1), rg[1].pb(0);///從入度為0的出發(fā)dfs1(0);for (int i = cnt; i >= 2; --i) {int u = rak[i];for (int v : rg[u]) {if(!dfn[v]) continue;Find(v);sdom[u] = min(sdom[u], sdom[val[v]]);}ufs[u] = fa[u];tg[rak[sdom[u]]].pb(u);for (int v : tg[fa[u]]) {Find(v);if(sdom[val[v]] == sdom[v]) idom[v] = rak[sdom[v]];else idom[v] = val[v];}tg[fa[u]].clear();}for (int i = 1; i <= cnt; ++i) {int u = rak[i];if(idom[u] != rak[sdom[u]]) idom[u] = idom[idom[u]];}for (int i = 1; i <= n; ++i) if(dfn[i]) G[idom[i]].pb(i);dfs2(0);LL ans = 0, tot = 1;for (int v : G[1]) {ans += sz[v]*tot;tot += sz[v];}printf("%lld\n", ans);
}
int n;
int main() {while(~scanf("%d", &n)) lengauer_tarjan(n);return 0;
}
轉(zhuǎn)載于:https://www.cnblogs.com/widsom/p/11367512.html
總結(jié)
以上是生活随笔為你收集整理的算法笔记--支配树的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。