链接:http://acm.hdu.edu.cn/showproblem.php?pid=6604
题意:T组样例。第一行给出n、m(n个点,m条单向边)。接下来m行描述这条边(给出u、v)u->v。再给一个q,表明q个询问,每个询问给出a、b。询问有多少点,那它去掉后,a、b中至少一个点不能到达出度为0的点。(也就是a或b到达所有出度为0的点的必经点的个数,在反向图中也就是所有入度为0的点到a或b的必经点的个数。)。题目说了该图是一个DAG。
思路:一个图是DAG的话,求必经点的个数就简单多了。我们逆向思考,如果我们建反向图,并且把反向图中入度为0的点(也就是原图中出度为0的点)和一个超级源点0(即支配树中的根节点)相连,那么这个有可能为森林的图,就变成了一棵树。这棵树就是我们需要的支配树。那么一个询问(a、b)的答案,就转化为求a、b的必经点的个数。由支配树的性质,一个点的必经点的个数就是其在支配树上到根节点的距离,那么答案就是deep[a]+deep[b]-deep[Lca(a,b)]。因此这个题,我们不必把支配树建出来,只需要记下支配树中每个点的深度和倍增找LCA所需要的信息即可。(具体参考https://blog.csdn.net/birdmanqin/article/details/97816603 很类似)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+10;
int deep[N],f[N][20],in[N],id[N],q[N],he,ta;
int n,m,root,num,u,v,Q;
vector<int> g[N];
void Init()
{
memset(f,0,sizeof(f));
for(int i=0;i<=n;i++)
in[i]=0,g[i].clear();
return ;
}
void TopoSort()
{
//把根节点的深度设为0,方便计算
deep[root]=0;
//根节点的父亲还是根节点
f[root][0]=root;
num=0;
he=ta=0;
for(int i=1;i<=n;i++)
if(!in[i]) q[ta++]=i;
while(he!=ta)
{
u=q[he++];
//记下每个拓扑序的点
id[++num]=u;
for(int i=0;i<g[u].size();i++)
{
v=g[u][i];
in[v]--;
if(!in[v])
{
q[ta++]=v;
}
}
}
return;
}
//倍增求LCA
int Lca(int x,int y)
{
if(deep[x]<deep[y])
swap(x,y);
int diff=deep[x]-deep[y];
for(int i=0;i<=17;i++)//从小往大找
if(diff&(1<<i)) x=f[x][i];
if(x==y) return x;
for(int i=17;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int main(void)
{
//cout<<(1<<17)<<endl;
root=0;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
Init();
//说反向图是为了好理解还是正向建图,
//因为后面要用到已经与其相连并且在支配树的点的LCA
//来确定每个点在支配树中的父亲。
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
in[v]++;
}
TopoSort();
//拓扑排序倒序建支配树
for(int i=n;i>=1;i--)
{
v=id[i];
//也就是出度为0的点,直接与根节点0相连
if(!g[v].size())
{
f[v][0]=root;
deep[v]=deep[root]+1;
continue;
}
u=g[v][0];
for(int j=1;j<g[v].size();j++)
u=Lca(u,g[v][j]);
deep[v]=deep[u]+1;
f[v][0]=u;
for(int i=1;i<=17;i++)
f[v][i]=f[f[v][i-1]][i-1];
}
scanf("%d",&Q);
while(Q--)
{
scanf("%d%d",&u,&v);
//因为我的根节点的深度为0,算出来刚好是答案
printf("%d\n",deep[u]+deep[v]-deep[Lca(u,v)]);
}
}
return 0;
}