zoukankan      html  css  js  c++  java
  • 题解 洛谷 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;
    }
    
  • 相关阅读:
    sublime c/c++ 环境
    sublime编写markdownm
    第八次课程作业
    第七次课程作业
    第六次作业
    第五次课程作业
    Arithmatic项目修改总结
    第四次课程作业
    第三次课程作业
    课程作业二
  • 原文地址:https://www.cnblogs.com/lhm-/p/13619510.html
Copyright © 2011-2022 走看看