AT_abc451_e [ABC451E] Tree Distance 题解
考虑直接构造一组合法的解。
由于树上两点的距离都给出了,且边权为正整数,所以显然是最多有一组解。
方便构造,考虑随便把一个点作为根,那么根到其他点的距离记作 \(b_u\)。
随手将所有点按 \(b\) 从小到大的顺序排序(不排好像也是一样的),那么如果能判断点 \(u\) 是否为 \(v\) 的祖先,那么 \(d_u\) 最小的祖先 \(u\) 就是 \(v\) 的父亲,就可以构造出整棵树。
当 \(u\) 是 \(v\) 的祖先时,有 \(b_v-b_u =a_{u,v}\)。
当 \(u\) 不是 \(v\) 的祖先时,有 \(b_v+b_u-2b_{lca}=a_{u,v}\),由于 \(b_{lca}<b_{u}\),所以 \(b_v-b_u\not =b_v+b_u-2b_{lca}=a_{u,v}\)。
所以,我们可以构造出一组解。
那么,再写个树上距离判断树是否符合 \(a\) 即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
int d=0,f=0;char ch=getchar();
while (!isdigit(ch)) f|=(ch=='-'),ch=getchar();
while (isdigit(ch)) d=d*10+ch-'0',ch=getchar();
return f?-d:d;
}
const int N=3005,M=N*N;
int n,a[N][N],b[N],p[N];
int fa[20][N],dep[N],h[N],idx=1,e[N],ne[N];
inline void add(int a,int b) {e[idx]=b,ne[idx]=h[a],h[a]=idx++;}
bool cmp(int x,int y){return b[x]<b[y];}
void dfs(int u){
for (int i=h[u];i;i=ne[i]){
int v=e[i];
dep[v]=dep[u]+1,fa[0][v]=u;
for (int j=1;(1<<j)<=dep[v];j++)
fa[j][v]=fa[j-1][fa[j-1][v]];
dfs(v);
}
}
inline int LCA(int x,int y) {
if (dep[x]<dep[y]) swap(x,y);
for (int i=19;i>=0;i--)
if (dep[x]-(1<<i)>=dep[y]) x=fa[i][x];
if (x==y) return x;
for (int i=19;i>=0;i--)
if (fa[i][x]!=fa[i][y] ) x=fa[i][x],y=fa[i][y];
return fa[0][x];
}
signed main(){
n=read();
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++) a[i][j]=a[j][i]=read();
for (int i=2;i<=n;i++) b[i]=a[1][i];
for (int i=1;i<=n;i++) p[i]=i;
sort(p+1,p+n+1,cmp);
for (int i=1;i<=n;i++)
for (int j=i-1;j>=1;j--)
if (b[i]-b[j]==a[i][j]) {add(j,i);break;}
dfs(1);
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++)
if (b[i]+b[j]-b[LCA(i,j)]*2!=a[i][j]) {puts("No");return 0;}
puts("Yes");
return 0;
}
比赛代码,实现不精细,还请见谅。
花絮
上周偶然做到一道 ad-hoc,P12826 「DLESS-2」XOR and Tree Construction。
然后和同学讨论改成路径和怎么做,结果这周考了...

浙公网安备 33010602011771号