典型的支配树裸题,就是询问给定点到某点i的全部路径都经过的某点j。
具体讲解就不写了,网上很详细。
安利1
安利2
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<algorithm>
using namespace std;
const int N=500001;
vector<int> E[N],G[N],V[N];
int son[N],dfn[N],idom[N],sdom[N],id[N],fa[N],f[N],ans[N],cnt;
int find(int x){
if(f[x]==x)return x;
int y=find(f[x]);
if(sdom[son[x]]>sdom[son[f[x]]])son[x]=son[f[x]];
return f[x]=y;
}
void dfs(int u){
id[dfn[u]=++cnt]=u;
for(register int v,i=0;i<E[u].size();i++)
if(v=E[u][i],!dfn[v])dfs(v),fa[dfn[v]]=dfn[u];
}
int n,m;
inline void tarjan(int s){
for(register int i=1;i<=n;i++)f[i]=sdom[i]=son[i]=fa[i]=i,dfn[i]=0;
cnt=0,dfs(s);
register int k,x;
for(register int i=cnt;i>1;i--){
for(register int v,j=0;j<G[id[i]].size();++j)
if(v=G[id[i]][j],dfn[v])
find(k=dfn[v]),sdom[i]=sdom[i]<sdom[son[k]]?sdom[i]:sdom[son[k]];
V[sdom[i]].push_back(i),f[i]=x=fa[i];
for(register int v,j=0;j<V[f[i]].size();j++)
v=V[f[i]][j],find(k=v),idom[k]=sdom[son[k]]<x?son[k]:x;
V[x].clear();
}
for(register int i=2;i<=cnt;V[id[idom[i]]].push_back(id[i]),i++)
if(idom[i]!=sdom[i])idom[i]=idom[idom[i]];
}
void mp(int u,int p){
ans[u]=p;
for(register int v,i=0;i<V[u].size();++i)
v=V[u][i],mp(v,p+v);
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
for(register int i=0;i<=500000;i++)G[i].clear(),V[i].clear(),E[i].clear();
for(register int u,v,i=1;i<=m;i++)scanf("%d%d",&u,&v),E[u].push_back(v),G[v].push_back(u);
tarjan(n),mp(n,n);
for(register int i=1;i<=n;i++)
printf("%d",ans[i]),putchar(i==n?'\n':' '),ans[i]=0;
}
return 0;
}