Linux 核心:裝置樹(1)dtb格式
阿新 • • 發佈:2021-06-29
luogu模版題都是黑的,離譜,瑟瑟發抖
一個有向圖,欽點一個點 s 為起點。對於兩個點 u,v 當刪除點 u 使得沒有從 s 到 v 的路徑存在時,我們稱 u 是 v 的支配點。容易發現,對於這種支配關係可以形成一個樹形結構,稱之為支配樹,支配樹的根節點是 s 。
樹
樹的支配樹就是他自己啦(
DAG
按照拓撲序進行處理,對於一個點 u ,他在支配樹中的父親是所有直接連向他的點 x 的LCA。
有向圖
有環了,難搞。
tarjan是真的神仙!!
首先隨便弄一個生成樹出來,並且標好dfn序。可以發現橫叉邊只會從dfn大的地方連向dfn小的地方等性質。
定義半支配點:當存在一條路徑 \(u \rightarrow v\)
我們需要求出對於一個點 u 的 dfn 序最小的半支配點 (semi)。
考慮有 \(w \rightarrow u\) 的情況,二者直接相連。
當 \(dfn[w] < dfn[u]\) 的時候,用 w 來更新 \(semi[u]\) 。
當 \(dfn[w] > dfn[u]\) 的時候,用 w 的 semi 以及他部分祖先的 semi 來更新 \(semi[u]\) 。對於可以更新 u 的 x,有 x 是 w 的本身及祖先且 \(dfn[x] > dfn[u]\)
使用帶權並查集來進行處理。每次處理完 u 將其連向原dfs樹中的father。
有一個性質,我們保留樹邊和邊 \((semi[u] \rightarrow u)\) 後,滅絕樹不變。
顯然這樣處理後是一個 DAG 。可以使用前面提到的 DAG 的做法進行求解即可。
luogu模版code:
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <vector> using namespace std; int read() { int a = 0,x = 1;char ch = getchar(); while(ch > '9' || ch < '0') {if(ch == '-') x = -1;ch = getchar();} while(ch >= '0' && ch <= '9') {a = a*10 + ch-'0';ch = getchar();} return a*x; } const int N=1e6+7; int n,m,head[N],go[N],nxt[N],cnt,anc[N],dfn[N],pos[N],du[N],fa[N],semi[N],mn[N],dp[N],dep[N],jump[N][20],siz[N]; void add(int u,int v) { go[++cnt] = v; nxt[cnt] = head[u]; head[u] = cnt; } vector<int>g[N],o[N]; void dfs(int u) { dfn[u] = ++cnt,pos[cnt] = u; for(int e = head[u];e;e = nxt[e]) { int v = go[e];if(dfn[v]) continue; anc[v] = u;g[u].push_back(v);du[v] ++; dfs(v); } } int find(int s) { if(fa[s] == s) return s; int tmp = find(fa[s]); mn[s] = dfn[semi[mn[s]]]<dfn[semi[mn[fa[s]]]] ? mn[s] : mn[fa[s]]; fa[s] = tmp;return tmp; } int LCA(int a,int b) { if(!a || !b) return a+b; if(dep[a] < dep[b]) swap(a,b); for(int i = 19;i >= 0;i --) if(dep[jump[a][i]] >= dep[b]) a = jump[a][i]; if(a == b) return a; for(int i = 19;i >= 0;i --) if(jump[a][i] != jump[b][i]) a = jump[a][i],b = jump[b][i]; return jump[a][0]; } void DFS(int u) { siz[u] = 1; for(int e = head[u];e;e = nxt[e]) { int v = go[e];DFS(v); siz[u] += siz[v]; } } int main() { // freopen("random.in","r",stdin);freopen("out.out","w",stdout); n = read(),m = read(); for(int i = 1;i <= m;i ++) { int u = read(),v = read(); add(u,v);o[v].push_back(u); } cnt = 0;dfs(1); for(int i = 1;i <= n;i ++) fa[i] = i,semi[i] = mn[i] = i; for(int i = n;i >= 2;i --) { for(int a:o[pos[i]]) { if(!dfn[a]) continue; if(dfn[a] < dfn[pos[i]]) semi[pos[i]] = dfn[semi[pos[i]]]>dfn[a]?a:semi[pos[i]]; else find(a),semi[pos[i]] = dfn[semi[pos[i]]]>dfn[semi[mn[a]]]?semi[mn[a]]:semi[pos[i]]; } g[semi[pos[i]]].push_back(pos[i]);du[pos[i]] ++;fa[pos[i]] = anc[pos[i]]; } for(int i = 1;i <= n;i ++) head[i] = 0;cnt = 0; queue<int>q;for(int i = 1;i <= n;i ++) if(!du[i] && dfn[i]) q.push(i); while(!q.empty()) { int u = q.front();q.pop(); jump[u][0] = dp[u],dep[u] = dep[dp[u]] + 1; if(dp[u]) add(dp[u],u); for(int i = 1;i < 20;i ++) jump[u][i] = jump[jump[u][i-1]][i-1]; for(int v:g[u]) { du[v] --;dp[v] = LCA(dp[v],u); if(!du[v]) q.push(v); } } DFS(1); for(int i = 1;i <= n;i ++) printf("%d ",siz[i]); return 0; }