题意:
给定一个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; }