树上最远点对(树的直径)
树形dp,类似要求出离任意一个点最远的点的方法。
最长路一定是经过树上的某一个节点的。ans[i]表示i点往下走的最长路。每个节点处都统计一下向下的最长和次长链,将两条拼接起来去更新答案。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 typedef long long LL; 7 struct Edge 8 { 9 LL to,dis,next; 10 }e[60010]; 11 LL ne,f1[30010]; 12 bool vis[30010]; 13 LL ans[30010],anss,T,TT,n; 14 void dfs(LL u) 15 { 16 vis[u]=true; 17 LL k=f1[u],v,ma1=0,ma2=0; 18 priority_queue<LL> q; 19 while(k!=0) 20 { 21 v=e[k].to; 22 if(!vis[e[k].to]) 23 { 24 dfs(v); 25 q.push(ans[v]+e[k].dis); 26 } 27 k=e[k].next; 28 } 29 if(!q.empty()) 30 ma1=q.top(),q.pop(); 31 if(!q.empty()) 32 ma2=q.top(),q.pop(); 33 anss=max(anss,ma1+ma2); 34 ans[u]=ma1; 35 } 36 int main() 37 { 38 LL i,u,v,w; 39 scanf("%lld",&TT); 40 for(T=1;T<=TT;T++) 41 { 42 memset(vis,0,sizeof(vis)); 43 memset(ans,0,sizeof(ans)); 44 ne=0; 45 anss=0; 46 memset(f1,0,sizeof(f1)); 47 scanf("%lld",&n); 48 for(i=1;i<n;i++) 49 { 50 scanf("%lld%lld%lld",&u,&v,&w); 51 e[++ne].to=v; 52 e[ne].next=f1[u]; 53 e[ne].dis=w; 54 f1[u]=ne; 55 e[++ne].to=u; 56 e[ne].next=f1[v]; 57 e[ne].dis=w; 58 f1[v]=ne; 59 } 60 dfs(0); 61 printf("Case %lld: %lld\n",T,anss); 62 } 63 return 0; 64 }
另:贪心做法&证明
只需要从任意点a1出发遍历整张图找到离a1最远的点u,再从u出发找到离u最远的点v,u到v的路径就是最长路。
同时可以发现一点:到树上任意一点的最长链,一定是这一点到u、v的链之一。(貌似并没有什么卵用,求树上两点距离是倍增的,比直接求到树上任意一点最长链还要难写)
时间: 2024-10-31 16:33:31