题目描述:
题解:
基环树拆环$dp$。
先找环拆环,令$dp[i]$表示环上点$i$不经过环的最长链,$sum[i]$表示环上按某一确定顺序遍历顶点到第$i$个点的距离。
这两个是基环树拆环后都要处理的。
在树形$dp$先处理不经过环的最长链。
然后处理经过环的。
我们可以处理:
- $max_{l<r leq i}{ l子树内最长链端点到r子树内最长链端点距离}$
- $max_{i leq l<r}{ l子树内最长链端点到r子树内最长链端点距离}$
- $max_{r leq i}{ r子树内最长链端点到第一个点子树内最长链端点距离}$
- $max_{i leq l}{ l子树内最长链端点到最后一个点子树内最长链端点距离}$
对于断每一条边我们都能$O(1)$出直径。
最后两个$ans$取最大输出即可。
时间复杂度$O(n)$。
$set$也有$O(nlogn)$做法但是不如这个官方解法优秀。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N = 200050; template<typename T> inline void read(T&x) { T f = 1,c = 0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x = f*c; } int n,hed[N],cnt=1; struct EG { int to,nxt; ll w; }e[2*N]; void ae(int f,int t,ll w) { e[++cnt].to = t; e[cnt].nxt = hed[f]; e[cnt].w = w; hed[f] = cnt; } int sta[2*N],tl,rt; ll ste[2*N]; bool cir[N]; bool vis[N]; int dfs0(int u,int pre) { if(vis[u]) { rt = u; return 1; } vis[u] = 1; for(int now,j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(j==pre)continue; if((now=dfs0(to,j^1))) { if(now==1) { sta[++tl] = u; ste[tl] = e[j].w; cir[u] = 1; if(u!=rt)return 1; } return 2; } } return 0; } ll dp[N],sum[2*N],ans=0x3f3f3f3f3f3f3f3fll,ans0; ll f[2][N],g[2][N]; ll dfs1(int u,int pre) { for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(j==pre||cir[to])continue; ll tmp = dfs1(to,j^1)+e[j].w; ans0 = max(ans0,dp[u]+tmp); dp[u] = max(dp[u],tmp); } return dp[u]; } int main() { // freopen("tt.in","r",stdin); read(n); for(int u,v,w,i=1;i<=n;i++) { read(u),read(v),read(w); ae(u,v,w),ae(v,u,w); } dfs0(1,0); for(int i=1;i<=tl;i++)dfs1(sta[i],0); for(int i=1;i<=tl;i++)sum[i]=sum[i-1]+ste[i]; ll mx = -ste[1]; for(int i=1;i<=tl;i++) { f[0][i] = max(f[0][i-1],dp[sta[i]]+sum[i]+mx); mx = max(mx,dp[sta[i]]-sum[i]); f[1][i] = max(f[1][i-1],dp[sta[i]]+sum[i]-sum[1]); } mx = sum[tl]; for(int i=tl;i>=1;i--) { g[0][i] = max(g[0][i+1],dp[sta[i]]-sum[i]+mx); mx = max(mx,dp[sta[i]]+sum[i]); g[1][i] = max(g[1][i+1],dp[sta[i]]-sum[i]+sum[tl]); } ans = f[0][tl]; for(int i=1;i<=tl;i++) ans = min(ans,max(max(f[0][i],g[0][i+1]),f[1][i]+g[1][i+1]+ste[1])); printf("%lld ",max(ans,ans0)); return 0; }