[SDOI2013]直径 题解
这道题明显的一定要找到直径的具体路径,所以两遍dfs是比较好的选择;
第一问是一道弱智题吧?
主要难度全部分摊在了第二问;
其实不难,先找到任意一个直径;
对于任意一个在直径上的点:
设nxt[i]表示这个点的下一个位置,pre[i]表示这个点的上一个位置;
ls[i]表示这个点到直径的左端点的距离,rs[i]则表示这个点到直径的右端点的距离;
我们再dfs一遍,找到每个点在不经过直径上任意点的时候所能到达的最远处,这个值记为dismax[i];
那么我们从直径的左端点开始向右推进,直到找到一个点的rs[i]=dismax[i](这意味着存在一条直径使得下一条边不是必经边);
我们注意到,从右向左也需要这么做一次。毕竟我们无法保证从左端点开始就是必经边;
然后就可以A掉了;
#include <bits/stdc++.h> #define int long long #define inc(i,a,b) for(register int i=a;i<=b;i++) using namespace std; const int MXR=2e5+10; int head[MXR],cnt; class littlestar{ public: int to,nxt,w; void add(int u,int v,int gg){ to=v; nxt=head[u]; w=gg;head[u]=cnt; } }star[MXR<<1]; int n,m; template<class nT> void read(nT& x) { char c;while(c=getchar(),!isdigit(c)); x=c^48;while(c=getchar(),isdigit(c)) x=x*10+c-48; } int dis[MXR],root1,root2,f[MXR],g[MXR]; void dfs(int u,int fa) { f[u]=fa; for(int i=head[u];i;i=star[i].nxt){ int v=star[i].to; if(v==fa) continue; dis[v]=dis[u]+star[i].w; dfs(v,u); g[v]=star[i].w; } } int judge[MXR],ls[MXR],rs[MXR],nxt[MXR],pre[MXR]; int dismax[MXR]; void dfs2(int u,int fa) { for(int i=head[u];i;i=star[i].nxt){ int v=star[i].to; if(v==fa) continue; dfs2(v,u); if(judge[v]==0){ dismax[u]=max(dismax[u],star[i].w+dismax[v]); } } } signed main() { read(n); inc(i,1,n-1){ int a,b,c; read(a);read(b);read(c); star[++cnt].add(a,b,c); star[++cnt].add(b,a,c); } root1=1; dfs(root1,0); int maxn=-INT_MAX; inc(i,1,n) if(dis[i]>maxn) maxn=dis[i],root2=i; memset(dis,0,sizeof(dis)); maxn=-INT_MAX; memset(f,0,sizeof(f)); dfs(root2,0); inc(i,1,n) if(dis[i]>maxn) maxn=dis[i],root1=i; int tmpx=root1; while(tmpx!=root2){ nxt[tmpx]=f[tmpx]; pre[f[tmpx]]=tmpx; ls[f[tmpx]]=ls[tmpx]+g[tmpx]; rs[tmpx]=maxn-ls[tmpx]; judge[tmpx]=1; tmpx=f[tmpx]; } judge[root2]=1; dfs2(root2,0); int goal=0; tmpx=root1; while(tmpx!=0){ if(rs[tmpx]==dismax[tmpx]){ break; } tmpx=nxt[tmpx]; } if(tmpx==0) tmpx=pre[tmpx]; goal=tmpx; while(tmpx!=0){ if(ls[tmpx]==dismax[tmpx]){ break; } tmpx=pre[tmpx]; } if(tmpx==0) tmpx=nxt[tmpx]; int ans=0; while(tmpx!=goal){ ++ans; tmpx=nxt[tmpx]; } cout<<maxn<<endl; cout<<ans; } /* 6 3 1 1000 1 4 10 4 2 100 4 5 50 4 6 100 */
众人皆醉我独醒,举世皆浊我独清