题解 洛谷 P4886 【快递员】

考虑一个节点成为根节点后,如何判断其为最优的。

若最长距离的路径中的任意一条满足两个端点在当前根节点的两个不同的儿子中,则当前根节点为最优的。因为若将其调整为不在该路径上的点,最长路径的值会变大,将其调整为该路径上别的点,可能会产生更长的路径,因此该根节点为最优的。

若存在两条最长距离的路径的端点不来自同一个儿子,则当前根节点为最优的。这也是可以用调整来证明的。

因此可以考虑点分治,当前根节点若是最优的就直接结束分治,否则就到最长距离的路径端点对应的那个儿子中,以该子树的重心作为下次的分治中心。

#include<bits/stdc++.h>
#define maxn 200010
#define inf 1000000000
using namespace std;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,m,ans=inf,root,tot,top;
int mx[maxn],siz[maxn],d[maxn],bel[maxn],st[maxn];
bool vis[maxn];
struct edge
{
    int to,nxt,v;
}e[maxn];
int head[maxn],edge_cnt;
void add(int from,int to,int val)
{
    e[++edge_cnt]={to,head[from],val},head[from]=edge_cnt;
}
struct query
{
    int x,y;
}q[maxn];
void dfs_root(int x,int fa)
{
    siz[x]=1,mx[x]=0;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(vis[y]||y==fa) continue;
        dfs_root(y,x),siz[x]+=siz[y];
        mx[x]=max(mx[x],siz[y]);
    }
    mx[x]=max(mx[x],tot-siz[x]);
    if(mx[x]<mx[root]) root=x;
}
void dfs_dis(int x,int fa,int dis,int rt)
{
    bel[x]=rt,d[x]=dis;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(y==fa) continue;
        dfs_dis(y,x,dis+e[i].v,rt);
    }
}
void solve(int x)
{
    vis[x]=true;
    for(int i=head[x];i;i=e[i].nxt)
        dfs_dis(e[i].to,x,e[i].v,e[i].to);
    int val=0,p;
    for(int i=1;i<=m;++i)
    {
        int v=d[q[i].x]+d[q[i].y];
        if(v>val) val=v,st[top=1]=i;
        else if(v==val) st[++top]=i;
    }
    ans=min(ans,val),p=bel[q[st[top]].x];
    if(vis[p]) return;
    for(int i=1;i<=top;++i)
    {
        int x=q[st[i]].x,y=q[st[i]].y;
        if(bel[x]!=bel[y]||bel[x]!=p) return;
    }
    root=0,tot=siz[p],dfs_root(p,x),solve(root);
}
int main()
{
    read(n),read(m);
    for(int i=1;i<n;++i)
    {
        int x,y,v;
        read(x),read(y),read(v);
        add(x,y,v),add(y,x,v);
    }
    for(int i=1;i<=m;++i) read(q[i].x),read(q[i].y);
    tot=mx[0]=n,dfs_root(1,0),solve(1),printf("%d",ans);
    return 0;
}
posted @ 2020-09-05 20:13  lhm_liu  阅读(212)  评论(0编辑  收藏  举报