有向無環圖的支配樹

支配樹:樹上的任何一個點的所有祖先都是在有向無環圖中這個點到樹根的所有路徑的必經點。
有向無環圖支配樹求法:
由於在有向無環圖中可能有很多聯通塊,所有需要先記錄入度,然後從每個入度爲0的點開始跑bfs,每個點在支配樹上的父親就是在有向無環圖中它的所有父親的LCA。

有向無環圖的支配樹模板題

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
const int MAX_N=100100;
vector<int>v[MAX_N];
int head[MAX_N],ver[2*MAX_N],Next[2*MAX_N];
int sum[MAX_N];
int tot,tt;
int deep[MAX_N];
int dp[MAX_N][20];
void Add(int x,int y){
	ver[++tot]=y;Next[tot]=head[x];head[x]=tot;
}
queue<int>q;
int LCA(int a,int b){
    int k=tt,i;
    if(deep[a]<deep[b])
    swap(a,b);
    while(deep[a]!=deep[b]){
        for(i=k;i>=0;i--){
            if(deep[dp[a][i]]>=deep[b])
            a=dp[a][i];
        }
    }
    if(a==b){
        return b;
    }
    for(i=k;i>=0;i--){
        if(dp[a][i]!=dp[b][i]){
            a=dp[a][i];
            b=dp[b][i];
        }
    }
    return dp[a][0];
}
void solve(int x){
	int lca=v[x][0];
	for(int i=1;i<v[x].size();i++){
		int y=v[x][i];
		lca=LCA(lca,y);
	}
	dp[x][0]=lca;
	deep[x]=deep[lca]+1;
	for(int i=1;i<=tt;i++)
	dp[x][i]=dp[dp[x][i-1]][i-1];
}
void topo(){
	int i;
	while(!q.empty()){
		int x=q.front();
		q.pop();
		for(i=head[x];i;i=Next[i]){
			int y=ver[i];
			sum[y]--;
			if(sum[y]==0){
				q.push(y);
				solve(y);
			}
		}
	}
}
int main(void){
	int n,m,i,x,y,qq;
	int T;
	cin>>T;
	while(T--){
	scanf("%d%d",&n,&m);
	tt=(int)(log(n+1)/log(2))+1;
	tot=0;
	for(i=1;i<=n+1;i++){
		head[i]=0;
		v[i].clear();
		sum[i]=0;
	}
	for(i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		Add(y,x);
		sum[x]++;
		v[x].push_back(y);
	}
	for(i=1;i<=n;i++){
		if(!sum[i]){
			Add(n+1,i);
			sum[i]++;
			v[i].push_back(n+1);
		}
	}
	deep[n+1]=1;
	q.push(n+1);
	topo();
	scanf("%d",&qq);
	for(i=0;i<qq;i++){
		scanf("%d%d",&x,&y);
		int lca=LCA(x,y);
		printf("%d\n",deep[x]+deep[y]-deep[lca]-1);
	}
	}
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章