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在支配树上的父亲。
性质:
-
- 每个点的半支配点是唯一的。
- 一个点的半支配点必定是它在dfs树上的祖先,dfn[semi[x]]<dfn[x]。
- 半支配点不一定是x的支配点。
- semi[x]的深度不小于idom[x]的深度,即idom[x]在semi[x]的祖先链上。
- 设节点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;
}