ICPC 2019-2020 North-Western Russia Regional Contest E. Equidistant(换根dp)
https://vjudge.net/problem/Gym-102411E
题意:
n个点的树上有m个特殊点,让你找到你一个点使得这个点到所有特殊点的距离相等。
思路
补:树的中心:该点到树中其他结点的最远距离 最近。
思路1
可以想到题目所求的点一定是树的中心,那么题意就变成:
- 找到树的中心
- 然后判断他是否所有到所有特殊点的距离相等即可。
也就是说:所有点距离相同等价于:
- 该点到 所有特殊节点 的最远距离 最近(树的中心)
- 该点到其他点的距离相同。
代码1
#include<bits/stdc++.h> using namespace std; #define int long long const int N=2e5+10, M = N * 2; const int inf = 1e9+7; int to[M], pre[M], h[N], idx; int d1[N], d2[N]; int fa1[N]; int up[N]; map<int,int> mp; void add(int a, int b) { to[idx] = b, pre[idx] = h[a], h[a] = idx++; } int a[N]; int dfs_d(int u,int f){ if(mp[u]) d1[u] =d2[u] = 0; else d1[u] = -inf , d2[u] = -inf; for(int i=h[u];i!=-1;i=pre[i]){ int j=to[i]; if(j==f) continue; int d=dfs_d(j,u)+1; if(d>d1[u]) { d2[u]=d1[u],d1[u]=d; fa1[u]=j; } else if(d>d2[u]) { d2[u]=d; } } return d1[u]; } void dfs_u(int u,int f){ for(int i=h[u];i!=-1;i=pre[i]){ int j=to[i]; if(j==f) continue; // cout<<j<<" " <<" " <<u<<" " <<up[u]<< " " <<d2[u]<<" "<<endl; if(fa1[u]==j){ up[j]=max(up[u],d2[u])+1; } else { up[j]=max(up[u],d1[u])+1; } dfs_u(j,u); } } int flag=1; int dist[N]; void dfs(int u,int v) { for(int i=h[u];i!=-1;i=pre[i]) { int j=to[i]; if(j==v) continue; dist[j]=dist[u]+1; dfs(j,u); // dist[u]+=dist[j]; } } signed main() { memset(h, -1, sizeof h); int n,m; cin>>n>>m; for(int i=0;i<n-1;i++){ int x,y;cin>>x>>y; add(x,y); add(y,x); } for(int i=0;i<m;i++) cin>>a[i], mp[a[i]]=1; // memset(ansd,0x3f3f,sizeof ansd); // memset(ansup,0x3f3f,sizeof ansup); dfs_d(1,-1); if(mp[1]==0 ) up[1] = -inf; dfs_u(1,-1); int minnn = 0x3f3f3f3f3f; int ans=0; for (int i = 1; i <= n; i++){ // cout<<i<<" " <<ans<<" "<<d1[i]<<" " <<up[i]<<endl; if(minnn>max(d1[i], up[i])){ minnn=max(d1[i], up[i]); ans=i; } } dfs(ans,-1); //cout<<minnn<<endl; for(int i=0;i<m;i++) { int x=a[i]; //cout<<dist[x]<<" "<<x<<endl; if(dist[x]!=minnn) flag=0; } if(flag){ cout<<"YES"<<endl; cout << ans << endl; } else cout<<"NO"<<endl; return 0; }
思路2
到所有特殊点的距离相同等价于该点到所有特殊节点的最远的距离和最近的距离相等。
那么题意就变成:用换根dp维护
- 该点到树中其他结点的最远距离。
- 该点到树中其他结点的最近距离。
然后找到最远的距离和最近的距离相等的点即可。
代码2
#include<bits/stdc++.h> #define mk make_pair #define pi pair<int,int> using namespace std; const int maxn = 2e5+10; int vis[maxn]; vector<int>G[maxn]; vector<pi>sf[maxn]; int mx[maxn],mn[maxn]; const int inf = 1e9+7; int ans ; void dfs(int u,int fa) { if(vis[u]) mx[u] = mn[u] = 0; else mx[u] = -inf , mn[u] = inf; for(auto v:G[u]) if(v!=fa) { dfs(v,u); mx[u] = max(mx[u],mx[v]+1); mn[u] = min(mn[u],mn[v]+1); } } void dfs2(int u,int fa) { if(ans) return; if(vis[u]) mx[u] = mn[u] = 0; else mx[u] = -inf , mn[u] = inf; sf[u].push_back(mk(mx[u],mn[u])); for(auto v:G[u]) { mx[u] = max(mx[u],mx[v]+1); mn[u] = min(mn[u],mn[v]+1); sf[u].push_back(mk(mx[u],mn[u])); } if(mx[u]==mn[u]){ ans = u;return ; } int maxn = -inf , minn = inf; for(int i=G[u].size()-1;i>=0;i--) { int v = G[u][i]; mx[u] = max(sf[u][i].first,maxn); mn[u] = min(sf[u][i].second,minn); maxn = max(maxn,mx[v]+1); minn = min(minn,mn[v]+1); if(v!=fa) dfs2(v,u); } } int main() { int n,m;scanf("%d%d",&n,&m); int u,v; for(int i=1;i<n;i++) { scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } int p; for(int i=1;i<=m;i++) { scanf("%d",&p); vis[p]++; } dfs(1,0); dfs2(1,0); if(ans) printf("YES\n%d\n",ans); else puts("NO"); }
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/16796578.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步