题意:给一棵n个点的树,给定。问有多少点对
满足从沿最短路径从u走到v,不会先经过x再经过y。
题解:用总路径数减去不合法的路径数。根据x和y是否在一条链上判断一下,两种情况不合法的点对分别用子树大小算一下就行。x和y在一条链上等价于,所以求一下LCA来判断。
也可以DFS两次(一次以x为根,一次以y为根),不合法的路径数就是第一次的乘以第二次的
。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=3e5+4;
int n,x,y;
struct Edge {
int v,nxt;
}e[N<<1];
int head[N],etot;
int siz[N];
int dep[N],f[19][N];
inline void adde(int u,int v) {
e[++etot].nxt=head[u],e[etot].v=v,head[u]=etot;
}
inline int read() {
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
inline void dfs(int p,int fa) {
siz[p]=1;
dep[p]=dep[fa]+1;
f[0][p]=fa;
for (int i=1;i<19;++i)
f[i][p]=f[i-1][f[i-1][p]];
for (int i=head[p];~i;i=e[i].nxt) {
int v=e[i].v;
if (v^fa) {
dfs(v,p);
siz[p]+=siz[v];
}
}
}
inline int lca(int a,int b) {
if (dep[a]<dep[b]) a^=b^=a^=b;
int d=dep[a]-dep[b];
for (int i=18;~i;--i)
if (d&(1<<i)) a=f[i][a];
if (a==b) return a;
for (int i=18;~i;--i)
if (f[i][a]^f[i][b]) {
a=f[i][a];
b=f[i][b];
}
return f[0][a];
}
ll ans;
int main() {
memset(head,-1,sizeof(head));
n=read(),x=read(),y=read();
for (register int i=1;i<n;++i) {
int u=read(),v=read();
adde(u,v);
adde(v,u);
}
dfs(1,0);
int fa=lca(x,y);
if (fa^x&&fa^y) ans=1ll*(n-1)*n-1ll*siz[x]*siz[y];
else {
if (dep[x]<dep[y]) x^=y^=x^=y;
int c;
for (int i=head[y];~i;i=e[i].nxt) {
int v=e[i].v;
if (v^f[0][y]&&lca(v,x)==v) {
c=v;
break;
}
}
ans=1ll*(n-1)*n-1ll*(siz[1]-siz[c])*siz[x];
}
cout<<ans<<endl;
return 0;
}