1. 程式人生 > 其它 >Linux 核心:裝置樹(1)dtb格式

Linux 核心:裝置樹(1)dtb格式

luogu模版題都是黑的,離譜,瑟瑟發抖

一個有向圖,欽點一個點 s 為起點。對於兩個點 u,v 當刪除點 u 使得沒有從 s 到 v 的路徑存在時,我們稱 u 是 v 的支配點。容易發現,對於這種支配關係可以形成一個樹形結構,稱之為支配樹,支配樹的根節點是 s 。

樹的支配樹就是他自己啦(

DAG

按照拓撲序進行處理,對於一個點 u ,他在支配樹中的父親是所有直接連向他的點 x 的LCA。

有向圖

有環了,難搞。

tarjan是真的神仙!!

首先隨便弄一個生成樹出來,並且標好dfn序。可以發現橫叉邊只會從dfn大的地方連向dfn小的地方等性質。

定義半支配點:當存在一條路徑 \(u \rightarrow v\)

,並且路徑上除 u,v 外的 dfn 都小於 \(dfn[v]\) 的時候,我們稱 u 是 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;
}