Important Sisters

http://acm.hdu.edu.cn/showproblem.php?pid=4694

题意:以n为出发点,求每个点支配的点的编号和。 

总结:

支配树:https://www.cnblogs.com/fenghaoran/p/dominator_tree.html

有一个有向图(可以有环),定下了一个节点为起点s。现在我们要求:从起点s出发,走向一个点p的所有路径中,必须要经过的点有哪些点{xp}。

定义:semi[x]叫x的半支配点。定义如下:

semi[x]=min{v | 有路径v=v0, v1, ..., vk=x使得dfn[vi]>dfn[x]对1<=i<=k-1成立}.(走dfn大于它的点);

定义:idom[x]表示支配x的点中深度最深的点,叫x的支配点,也叫idom[x]支配了x。idom[x]就是x在支配树上的父亲。

性质:

    1. 每个点的半支配点是唯一的。
    2. 一个点的半支配点必定是它在dfs树上的祖先,dfn[semi[x]]<dfn[x]。
    3. 半支配点不一定是x的支配点。
    4. semi[x]的深度不小于idom[x]的深度,即idom[x]在semi[x]的祖先链上。
    5. 设节点v,w满足v->w。则v->idom[w]或者idom[w]->idom[v](a->b表示a在b的祖先链上)。
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <set>
#include <map>
#include <stack>
//#include <tr1/unordered_map>
#include <unordered_map>
#include <cmath>
#include<bits/stdc++.h>
using namespace std;

#define sfi(i) scanf("%d",&i)
#define sfl(i) scanf("%I64d",&i)
#define sfs(i) scanf("%s",(i))
#define pri(i) printf("%d\n",i)
#define prl(i) printf("%I64d\n",i)
#define sff(i) scanf("%lf",&i)
#define ll long long
#define ull unsigned long long
#define uint unsigned int
#define mem(x,y) memset(x,y,sizeof(x))
#define INF 0x3f3f3f3f
#define inf 8e19
#define eps 1e-10
#define PI acos(-1.0)
#define lowbit(x) ((x)&(-x))
#define fl() printf("flag\n")
#define MOD(x) ((x%mod)+mod)%mod
#define endl '\n'
#define pb push_back
#define lson (rt<<1)
#define rson (rt<<1|1)
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)

template<typename T>inline void read(T &x)
{
    x=0;
    static int p;p=1;
    static char c;c=getchar();
    while(!isdigit(c)){if(c=='-')p=-1;c=getchar();}
    while(isdigit(c)) {x=(x<<1)+(x<<3)+(c-48);c=getchar();}
    x*=p;
}

//-----------------------------------------------
const int maxn=5e4+9;
const int maxm=1e5+9;
const int mod=1e9+7;

int n,m;

int clo,dfn[maxn],fa[maxn],semi[maxn],idom[maxn],rev[maxn];
int ans[maxn];
struct node
{
    int to,nex;
};

struct G
{
    node E[maxm];
    int head[maxn],tot;
    inline void init()
    {
        tot=0;
        for(int i=0;i<=n;i++) head[i]=-1;
    }
    inline void addedge(int u,int v)
    {
        E[++tot]=(node){v,head[u]};
        head[u]=tot;
    }
}pre,nxt,dom;

struct Uset
{
    int fa[maxn],Mi[maxn];
    inline void init()
    {
        for(int i=1;i<=n;i++) fa[i]=Mi[i]=semi[i]=i;
    }
    inline int Find(int x)
    {
        if(fa[x]==x) return x;
        int fx=fa[x],y=Find(fa[x]);
        if(dfn[semi[Mi[fx]]]<dfn[semi[Mi[x]]]) Mi[x]=Mi[fx];
        return fa[x]=y;
    }
}uset;

inline void tarjan(int u)
{
    dfn[u]=++clo;rev[clo]=u;
    for(int i=nxt.head[u];i!=-1;i=nxt.E[i].nex)
    {
        int v=nxt.E[i].to;
        if(!dfn[v])
            fa[v]=u,tarjan(v);
    }
}

inline void build()
{
    for(int i=n;i>=2;i--)
    {
        int y=rev[i],tmp=n;
        if(!y) continue;
        for(int j=pre.head[y];j!=-1;j=pre.E[j].nex)
        {
            int x=pre.E[j].to;
            if(!dfn[x]) continue;
            if(dfn[x]<dfn[y]) tmp=min(tmp,dfn[x]);
            else uset.Find(x),tmp=min(tmp,dfn[semi[uset.Mi[x]]]);
        }
        semi[y]=rev[tmp];
        uset.fa[y]=fa[y];
        dom.addedge(semi[y],y);

        y=rev[i-1];
        if(!y) continue;
        for(int j=dom.head[y];j!=-1;j=dom.E[j].nex)
        {
            int x=dom.E[j].to;
            uset.Find(x);
            if(semi[uset.Mi[x]]==y) idom[x]=y;
            else idom[x]=uset.Mi[x];
        }
    }
    for(int i=2;i<=n;i++)
    {
        int x=rev[i];
        if(idom[x]!=semi[x])
            idom[x]=idom[idom[x]];
    }
    dom.init();

    for(int i=2;i<=n;i++)
    {
        dom.addedge(idom[rev[i]],rev[i]);
    }

}

inline void dfs(int u,int sum)
{
    ans[u]=sum+u;
    for(int i=dom.head[u];i!=-1;i=dom.E[i].nex)
    {
        int v=dom.E[i].to;
        dfs(v,sum+u);
    }

}


int main()
{
    //FAST_IO;

    //freopen("input.txt","r",stdin);

    while(~scanf("%d%d",&n,&m))
    {

        pre.init();
        nxt.init();
        dom.init();
        for(int i=0;i<=n;i++) ans[i]=dfn[i]=fa[i]=semi[i]=idom[i]=rev[i]=0;
        clo=0;

        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            nxt.addedge(u,v);
            pre.addedge(v,u);
        }

        tarjan(n);
        uset.init();
        build();

        dfs(n,0);
        for(int i=1;i<=n;i++)
        {
            if(i!=1) printf(" ");
            printf("%d",ans[i]);
        }
        printf("\n");

    }


    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值