Codeforces

Luogu

分析

显然选的路径是直径的一部分。为了方便,把直径上的点重编号为 $1\sim cnt$。

我们把这棵树想象成一条链上挂了一些子树。那么设一个 $maxdis_i$ 表示 $i$ 子树中到 $i$ 最远的点的距离。

一个暴力做法是枚举选的路径 $[l,r]$,此时最大距离就是 $1\sim l$ 的距离、$r\sim cnt$ 的距离、$\max_{i=l}^r\left\{maxdis_i\right\}$ 三者的最大值。这样子大概是 $O(n^3)$ 的。

考虑到我们选的路径一定越长越好,因此只需要枚举左端点 $l$,右端点即为 $l+k-1$。这样子就变成 $O(n^2)$ 了。

剩下的就很简单了。我们用 ST 表求 $maxdis$ 的最大值,这样就是 $O(n\log n)$ 的了。

代码

// ===================================
//   author: M_sea
//   website: http://m-sea-blog.com/
// ===================================
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define re register
using namespace std;

inline int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int N=100000+10;

int n,k;

struct edge { int v,w,nxt; } e[N<<1];
int head[N];
inline void addEdge(int u,int v,int w) {
    static int cnt=0;
    e[++cnt]=(edge){v,w,head[u]},head[u]=cnt;
}

int rt1,rt2;
int dis[N],fa[N];
inline void dfs1(int u,int f) {
    if (dis[u]>dis[rt1]) rt1=u;
    for (re int i=head[u];i;i=e[i].nxt)
        if (e[i].v!=f) dis[e[i].v]=dis[u]+e[i].w,dfs1(e[i].v,u);
}
inline void dfs2(int u,int f) {
    fa[u]=f;
    if (dis[u]>dis[rt2]) rt2=u;
    for (re int i=head[u];i;i=e[i].nxt)
        if (e[i].v!=f) dis[e[i].v]=dis[u]+e[i].w,dfs2(e[i].v,u);
}

int cnt=0,lend=0;
int in[N],maxdis[N],w[N];
int lg[N],st[17][N],sum[N];
inline void dfs3(int u,int f) {
    for (re int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v; if (v==f) continue;
        w[v]=e[i].w,dfs3(v,u);
        if (!in[v]) maxdis[u]=max(maxdis[u],maxdis[v]+e[i].w);
    }
}
inline void init_diameter() {
    for (re int i=rt2;i;i=fa[i]) in[i]=1,++cnt;
    dfs3(rt1,0);
    for (re int i=2;i<=n;++i) lg[i]=lg[i>>1]+1;
    for (re int i=rt2,j=1;i;i=fa[i],++j) st[0][j]=maxdis[i];
    for (re int i=1;i<17;++i)
        for (re int j=1;j+(1<<i)-1<=cnt;++j)
            st[i][j]=max(st[i-1][j],st[i-1][j+(1<<(i-1))]);
    for (re int i=rt2,j=1;i;i=fa[i],++j) sum[j]=w[i],lend+=w[i];
    for (re int i=1;i<=cnt;++i) sum[i]+=sum[i-1];
}
inline int query(int l,int r) {
    int t=lg[r-l+1];
    return max(st[t][l],st[t][r-(1<<t)+1]);
}

int main() {
    n=read(),k=read();
    if (n==1) { puts("0"); return 0; }
    for (re int i=1;i<n;++i) {
        int u=read(),v=read(),w=read();
        addEdge(u,v,w),addEdge(v,u,w);
    }
    dfs1(1,0),dfs2(rt1,0);
    init_diameter();
    if (k>cnt) printf("%d\n",query(1,cnt));
    else {
        int ans=2e9;
        for (re int i=1;i+k-1<=cnt;++i) {
            int tmp=max(sum[i-1],lend-sum[i+k-2]);
            ans=min(ans,max(tmp,query(i,i+k-1)));
        }
        printf("%d\n",ans);
    }
    return 0;
}
最后修改:2021 年 03 月 23 日 10 : 21 PM