HDU 4694 [支配树]

题目传送门

典型的支配树裸题,就是询问给定点到某点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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值