杭电2019多校第三场 HDU-6604 Blow up the city(支配树+必经点个数)

链接: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 
#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 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=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)<=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

 

 

你可能感兴趣的:(=====图论=====,=====数据结构=====,支配树)