Codeforces 979C

题意:

给定一个n个点,n-1条边的无向图,途中任意两点联通,并给出节点x,y,计算图上两点(u,v)之间的最短路径依次经过x,y的对数,(u,v)与(v,u)视作不同一对,求总对数-符合条件的对数

-------------------------------------------------------------------------------------------------------

Solution:

显然这个图是一棵树, 由于是无向图,可以将图中任意一个节点作为树根建树

那么可以将y作为树根,x则是树y的某一个节点,

设s[i]为子树i的size(包括i本身),节点z为(y,x)路径上y的儿子节点

符合条件的对数为(y,x)路径两端的节点数相乘,即s[x]*(s[y]-s[z]),用n(n-1)减去就可以得出答案

------------------------------------------------------------------------------------------------------

邻接表存图,s[]用递归的dfs完成,寻找而节点z同样用dfs的递归标记

------------------------------------------------------------------------------------------------------

Code:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <set>
#include <queue>
#define ll long long
using namespace std;
const int MAXN=3e5+10;
int n,x,y,z;
int head[MAXN],nume;
int size[MAXN];
bool tag[MAXN],vis[MAXN];
struct Edge
{
	int nex,to;
}e[MAXN*2];
inline int in()
{
	int x=0,flag=1;
	char ch=getchar();
	while (ch<'0'||ch>'9') {if (ch=='-') flag=-1;ch=getchar();}
	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x*flag;
}
void addedge(int from,int to)
{
	e[++nume]=(Edge){head[from],to};
	head[from]=nume;
}
int dfs(int u)
{
	vis[u]=true;
	size[u]++;
	if (u==x) tag[u]=true;
	for (int i=head[u];i;i=e[i].nex)
	{
		int v=e[i].to;
		if (!vis[v])
		{
			dfs(v);
			size[u]+=size[v];
			if (tag[v]) 
			{
				tag[u]=1;
				if (u==y) z=v;
			}
		}
	}
}
int main()
{
	n=in();
	x=in();y=in();
	for (int i=1;i<n;i++)
	{
		int u=in(),v=in();
		addedge(u,v);
		addedge(v,u);
	}
	dfs(y);
	cout<<(ll)n*(n-1)-(ll)size[x]*(size[y]-size[z]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wangyc123456/article/details/80318442