P13824 「Diligent-OI R2 D」在水一方 题解

· · 题解

事先声明:

文中树上距离指两点之间简单路径的长度,直接距离指「NC2 距离」,即欧几里得距离的平方。

题面解释:

## 思路分析: 观察到 $n=1000$,极大可能是 $O(n^2\log n)$ 的时间复杂度(后来的实践证明这是正确的)。 考虑枚举点对,如果已经预处理出树上距离以及两点所需要的最小的 $d$,我们可以对点对依次按距离降序、$i$ 升序、$j$ 升序进行排序,对询问离线后按 $d$ 降序排序,只需要枚举点对即可得到答案。 那么先预处理两点树上距离。首先,$i,j$ 的树上简单路径为 $i\sim lca$ 与 $j\sim lca$ 之和,所以我们只需要计录每个节点到根节点的树上距离,易得任意两点树上距离(此处本人使用倍增法求树上最近公共祖先)。 然后预处理两点所需最小的 $d$,根据定义就是 $i,j$ 向上移动时直接距离的最小值。这里明显可以 `DP` 实现。定义 $fa_i$ 为 $i$ 的父节点,$dis_{i,j}$ 为两点直接距离,$dp_{i,j}$ 意义如所求值。有: $$dp_{i,j}=\max(\min (dp_{fa_i,j},dp_{i,fa_j},dp_{fa_i,fa_j}),dis_{i,j})$$ 由于实现时需保证父节点已完成转移,此处本人使用`bfs`转移(`dfs`应该也可行)。 ## AC Code: 赛时代码,实现十分丑陋,将就看吧。 ```cpp #include<bits/stdc++.h> #define int long long using namespace std; const int N=1010; int n,t,x[N],y[N],dis[N][N],mp[N][N],st[N][40]; int dep[N],lca[N][N],w[N],len[N][N],res[N*N]; bool vis[N][N];vector<int>g[N]; void dfs(int u,int fa){ st[u][0]=fa,dep[u]=dep[fa]+1; w[u]=w[fa]+dis[u][fa]; for(int v:g[u]) if(v!=fa)dfs(v,u); } struct S{int len,u,v,d;}ans[N*N]; inline bool cmp(S p,S q){ return(p.len^q.len?p.len>q.len:p.u^q.u?p.u<q.u:p.v<q.v); } struct node{int u,v,rt;}; struct qry{int val,id;}r[N*N]; inline bool cmp2(qry p,qry q){ return p.val>q.val; } queue<node>q; signed main() { ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); cin>>n>>t; for(int i=1;i<=n;i++) cin>>x[i]>>y[i]; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dis[i][j]=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]); for(int i=1,u,v;i<n;i++) cin>>u>>v, g[u].push_back(v), g[v].push_back(u); dfs(1,1); for(int i=1;i<=30;i++) for(int j=1;j<=n;j++) st[j][i]=st[st[j][i-1]][i-1]; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ int u=i,v=j; if(dep[u]<dep[v])swap(u,v); for(int i=30;i>=0;i--) if(dep[st[u][i]]>=dep[v])u=st[u][i]; if(u==v){lca[i][j]=u;continue;} for(int i=30;i>=0;i--) if(st[u][i]!=st[v][i]) u=st[u][i],v=st[v][i]; lca[i][j]=st[u][0]; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) mp[i][j]=1000000000000000; for(int i=1;i<=n;i++) mp[i][i]=0,q.push({i,i,i}); while(!q.empty()){ int u=q.front().u,v=q.front().v,rt=q.front().rt; q.pop(); for(int U:g[u]) if(U!=st[u][0]&&lca[U][v]==rt){ mp[U][v]=min(mp[U][v],max(mp[u][v],dis[U][v])); if(!vis[U][v])vis[U][v]=1,q.push({U,v,rt}); } for(int V:g[v]) if(V!=st[v][0]&&lca[u][V]==rt){ mp[u][V]=min(mp[u][V],max(mp[u][v],dis[u][V])); if(!vis[u][V])vis[u][V]=1,q.push({u,V,rt}); } for(int U:g[u])if(U!=st[u][0]) for(int V:g[v])if(V!=st[v][0]) if(lca[U][V]==rt){ mp[U][V]=min(mp[U][V],max(mp[u][v],dis[U][V])); if(!vis[U][V])vis[U][V]=1,q.push({U,V,rt}); } } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) len[i][j]=w[i]+w[j]-2*w[lca[i][j]], ans[(i-1)*n+j]={len[i][j],i,j,mp[i][j]}; sort(ans+1,ans+n*n+1,cmp); for(int i=1;i<=t;i++)cin>>r[i].val,r[i].id=i; sort(r+1,r+t+1,cmp2); int i=1,j=1; while(j<=t) if(ans[i].d<=r[j].val)res[r[j++].id]=i; else i++; for(int i=1;i<=t;i++) cout<<ans[res[i]].u<<' '<<ans[res[i]].v<<'\n'; return 0; } ``` 完结撒花!!!