3066 快餐店

Task
有n个点,n条边,任意两点相互连通。在任意边的任意位置可设置A点,求A到n个点的距离中的最大值的最小值。

N<=1e5,边长l<=1e9

Solution
最后的答案一定在某一条边上,可以终态枚举。到每个点的距离是最短路径的问题,可以用dijksra来处理。但是怎么确定应该放在这条边的哪个位置呢?
边可以分类为链边,环边,如果在环边上dijkstra会怎么样呢?
这里写图片描述

一定会从源点从两端往中间更新。点A在一段线段中,假设左边长为x,那么右边长为d-x。
用这两个端点去dijkstra,一定会存在一个分界点,由图中不同颜色的箭头去更新。
也许可以在一条边上三分一个位置,但是30min+,无果。

如果在树上,确定一个点到每个点的距离的最大值最小,那么这个点一定是树的中心,以前树网的核中有做过,而且这个核在任意一条直径的中间。

怎么把一个基环外向树变成一棵普通的树呢?
——删去一条边。这条边就是dijkstra中一定更新不到的无用边。

因此基本的思路就是枚举断开环上的一条边,求树的直径。复杂度是O(N^2),超时了。

可以用线段树优化。
可以把环扩展2倍成链,把环上每一个点对应小树的最大距离压缩在这个点上。
最后答案为取一段长度为cirn的区间,使这个区间的直径最小。
Dis=sum[y]-sum[x-1]+mx[x]+mx[y],y>x
Sum[y]-sum[x-1]代表x到y的距离,再加上x,y各自小树对应的最长的距离,就是这个区间的直径。
可以n^2枚举这个区间的两个端点。但是也可以分治,如果把这个区间分成做区间和右区间,
那么左右端点只有可能
① 都在左区间
② 都在右区间
③ 一个在左区间,一个在右区间。
类似最优贸易简化版那道题。
最后别忘了,这个区间的直径也可能是小树的直径。

const int M=2e5+5;
ll mx[M<<1],sum[M<<1],val[M];
bool mark[M];
int id[M<<1],head[M],cnt[M],d[M];//100w
/*
    链上的点代表一棵树,mx记录直径
    val 这个点对应的小树内的直径 
    d 链上相邻两点间的距离 
*/
int n,ecnt,cirn,S,X;
struct edge{
    int t,v,nxt;
}e[M<<1];
inline void addedge(int f,int t,int v){
    e[++ecnt]=(edge){t,v,head[f]};
    head[f]=ecnt;
}
inline void input(){//建边 
    int i,j,k,a,b,c;
    rd(n);
    rep(i,1,n){
        rd(a);rd(b);rd(c);
        addedge(a,b,c);
        addedge(b,a,c);
        cnt[a]++;cnt[b]++;
    }
}
inline void Topo(){//找到不在环上的点 
    int i,j,k,x;
    queue<int>Q;
    while(!Q.empty())Q.pop();
    rep(i,1,n)if(cnt[i]==1)Q.push(i);//叶子节点
    while(!Q.empty()){
        x=Q.front();Q.pop();
        mark[x]=1;
        for(i=head[x];i;i=e[i].nxt)
            if(--cnt[e[i].t]==1)Q.push(e[i].t);
    } 
}
inline void findmx(int f,int x,ll d){
    if(d>mx[S]){X=x;mx[S]=d;}
    for(int i=head[x];i;i=e[i].nxt)
        if(e[i].t!=f&&mark[e[i].t])findmx(x,e[i].t,e[i].v+d);
}
inline void findcircle(int f,int x,int dis){
    d[cirn]=dis;
    if(x==S&&f)return;
    id[++cirn]=x;
    for(int i=head[x];i;i=e[i].nxt){
        int t=e[i].t;
        if(t==f||mark[t])continue;
        findcircle(x,t,e[i].v);
        break;
    }
}
inline void findval(int f,int x,ll d){
    if(d>val[S])val[S]=d;
    for(int i=head[x];i;i=e[i].nxt){
        int t=e[i].t;
        if(t==f||!mark[t]&&t!=id[S])continue;
        findval(x,t,d+e[i].v);
    }
}
inline void Circle(){
    int i,j,k,x,t,f;
    rep(i,1,n)if(!mark[i]){t=i;break;}//环上的点
    S=x=t;
    findcircle(0,x,0);
    rep(i,1,cirn){
        S=i;
        findmx(0,id[i],0);
        findval(0,X,0);
    }
    rep(i,cirn+1,cirn<<1){
        id[i]=id[i-cirn];
        mx[i]=mx[i-cirn];
        d[i]=d[i-cirn];
        val[i]=val[i-cirn];
    }
    rep(i,1,cirn<<1)sum[i]=sum[i-1]+d[i-1];
}
struct Tree{
    ll mi,mx,v;
    inline void clear(){
        mi=1e18;
        mx=-1;
        v=0;
    }
}ANS;
struct Segment_Tree{
    Tree t[M<<4];//480w
    inline Tree up(Tree &L,Tree &R){
        Tree C;
        C.v=max(R.mx-L.mi,max(L.v,R.v));
        C.mx=max(L.mx,R.mx);
        C.mi=min(L.mi,R.mi);
        return C;
    }
    inline void build(int l,int r,int p){
        if(l==r){
            t[p].mi=sum[l]-mx[l];
            t[p].mx=sum[l]+mx[l];
            t[p].v=val[l];
            return;
        }
        int mid=l+r>>1;
        build(l,mid,lsn(p));
        build(mid+1,r,rsn(p));
        t[p]=up(t[lsn(p)],t[rsn(p)]);
    }
    inline void query(int l,int r,int L,int R,int p){
        if(l==L&&r==R){
            ANS=up(ANS,t[p]);
            return;
        }
        int mid=L+R>>1;
        if(r<=mid)query(l,r,L,mid,lsn(p));
        else if(l>mid)query(l,r,mid+1,R,rsn(p));
        else query(l,mid,L,mid,lsn(p)),query(mid+1,r,mid+1,R,rsn(p));
    }
}T;
inline void solve(){
    int i,j,k;
    ll ans=-1;
    ANS.clear();
    rep(i,1,cirn){
        ANS.clear();
        T.query(i,i+cirn-1,1,cirn<<1,1);
//      printf("    %d %d %lld\n",i,i+cirn-1,ANS.v);
        MIN(ans,ANS.v);
    }
    db res=1.0*ans/2;
    printf("%.1lf\n",res);
}
int main(){
    /* 16.03 Today is a happy day ll 
        基环外向树
    */
//  freopen("foodshop0.in","r",stdin);
    input();
    Topo();
    Circle();
    T.build(1,cirn<<1,1);
    solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值