传送门

注意到答案为这个基环树直径\(/2\)

因为是基环树,所以考虑把环拎出来.如果直径不过环上的边,那么可以在环上每个点下挂的子树内\(dfs\)求得.然后如果过环上的边,那么环上的部分也是一条链,考虑拆环为链,现在问题是一条链,每个点往下延伸若干长度,问最远的距离.每个点往下最长的长度可以随便预处理,然后最长的路径一定是两个点以及往下延伸的路径+在链上两点之间的路径,也可以看成这条长链+前面那个点往下的链-前面链的部分+后面那个点往下的链-后面链的部分,所以可以维护两棵线段树,分别维护 点往下的链-前面链的部分 以及 点往下的链-后面链的部分,然后第一棵树的最大值和第二棵的最大值加长链长度就可以更新答案.然后每次删掉最前面那个点,加到链的最后面,两个线段树分别区间修改即可.

注意如果第一棵树的前缀最大值是最后一个点,那么要用第二棵树最大值+第一棵树到第二棵树最大值前面一位的前缀最大值更新答案

#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long
#define il inline using namespace std;
const LL N=1e5+10,mod=1e9+7;
il LL rd()
{
LL x=0,w=1;char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int to[N<<1],nt[N<<1],w[N<<1],hd[N],tot=1;
void add(int x,int y,int z)
{
++tot,to[tot]=y,nt[tot]=hd[x],w[tot]=z,hd[x]=tot;
++tot,to[tot]=x,nt[tot]=hd[y],w[tot]=z,hd[y]=tot;
}
int n,m,st[N][2],tp;
LL cr[N][2],de[N],dp[N];
bool v[N],ic[N];
bool d1(int x,int ffa)
{
if(v[x])
{
while(tp)
{
cr[++m][0]=st[tp][0],cr[m][1]=st[tp][1];
ic[st[tp][0]]=1;
if(st[tp][0]==x) break;
--tp;
}
return 1;
}
v[x]=1,st[++tp][0]=x;
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==ffa) continue;
st[tp][1]=w[i];
if(d1(y,x)) return 1;
}
--tp;
return 0;
}
void d2(int x,int ffa)
{
st[++tp][0]=x;
dp[x]=de[x];
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(ic[y]||y==ffa) continue;
de[y]=de[x]+w[i],d2(y,x),dp[x]=max(dp[x],dp[y]);
}
}
#define mid ((l+r)>>1)
struct SegmentTree
{
LL s[N<<3],tg[N<<3];
int lc[N<<3];
void ad(int o,LL x){s[o]+=x,tg[o]+=x;}
void psup(int o){s[o]=max(s[o<<1],s[o<<1|1]),lc[o]=s[o<<1]>=s[o<<1|1]?lc[o<<1]:lc[o<<1|1];}
void psdn(int o){if(tg[o]) ad(o<<1,tg[o]),ad(o<<1|1,tg[o]),tg[o]=0;}
void modif(int o,int l,int r,int ll,int rr,LL x)
{
if(ll<=l&&r<=rr){ad(o,x);return;}
psdn(o);
if(ll<=mid) modif(o<<1,l,mid,ll,rr,x);
if(rr>mid) modif(o<<1|1,mid+1,r,ll,rr,x);
psup(o);
}
void modif(int o,int l,int r,int lx,LL x)
{
if(l==r){ad(o,x);return;}
psdn(o);
if(lx<=mid) modif(o<<1,l,mid,lx,x);
else modif(o<<1|1,mid+1,r,lx,x);
psup(o);
}
LL quer(int o,int l,int r,int ll,int rr,int &lx)
{
if(ll<=l&&r<=rr) {lx=lc[o];return s[o];}
psdn(o);
LL a1=-(1ll<<50),a2=-(1ll<<50);
int l1=0,l2=0;
if(ll<=mid) a1=quer(o<<1,l,mid,ll,rr,l1);
if(rr>mid) a2=quer(o<<1|1,mid+1,r,ll,rr,l2);
psup(o);
lx=a1>=a2?l1:l2;
return max(a1,a2);
}
void bui(int o,int l,int r)
{
if(l==r){lc[o]=l;return;}
bui(o<<1,l,mid),bui(o<<1|1,mid+1,r);
psup(o);
}
}tr1,tr2; int main()
{
n=rd();
for(int i=1;i<=n;++i)
{
int x=rd(),y=rd(),z=rd();
add(x,y,z);
}
d1(1,0);
LL dn=0;
for(int i=1;i<=m;++i)
{
tp=0;
d2(cr[i][0],0);
LL nw=dp[cr[i][0]];
//printf("%lld %lld\n",nw,cr[i][1]);
int x=0;
while(tp)
{
if(de[st[tp][0]]==nw) {x=st[tp][0];break;}
--tp;
}
tp=0;
ic[cr[i][0]]=0;
de[x]=0,d2(x,0);
ic[cr[i][0]]=1;
dn=max(dn,dp[x]);
dp[cr[i][0]]=nw;
}
LL ln=0,ans=1ll<<50;
tr1.bui(1,1,m+m+1),tr2.bui(1,1,m+m+1);
for(int ll=1-m,rr=0;rr<m+m;)
{
if(ll>0) tr1.modif(1,1,m+m+1,ll,rr,cr[ll%m+1][1]),ln-=cr[ll%m+1][1];
++ll;
if(rr>0) ln+=cr[rr%m+1][1],tr2.modif(1,1,m+m+1,max(ll,1),rr,-cr[rr%m+1][1]);
++rr;
tr1.modif(1,1,m+m+1,rr,dp[cr[(rr-1)%m+1][0]]-ln),tr2.modif(1,1,m+m+1,rr,dp[cr[(rr-1)%m+1][0]]);
if(ll>0)
{
int lx=0,ee;
LL dt=ln+tr1.quer(1,1,m+m+1,ll,rr,lx);
if(lx<rr) dt+=tr2.quer(1,1,m+m+1,lx+1,rr,ee);
LL d2=ln+tr2.quer(1,1,m+m+1,ll,rr,lx);
if(lx>ll) d2+=tr1.quer(1,1,m+m+1,ll,lx-1,ee);
ans=min(ans,max(dt,d2));
}
}
ans=max(ans,dn);
printf("%lld.%lld\n",ans>>1,5*(ans&1));
return 0;
}

luogu P1399 [NOI2013]快餐店的更多相关文章

  1. P1399 [NOI2013] 快餐店 方法记录

    原题题面P1399 [NOI2013] 快餐店 题目描述 小 T 打算在城市 C 开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小 T 希望快餐店的地址选在离最 ...

  2. P1399 [NOI2013]快餐店

    传送门 基环树的题当然先考虑树上怎么搞,直接求个直径就完事了 现在多了个环,先把非环上的直径(设为 $ans$)和环上节点 $x$ 到叶子的最大距离(设为 $dis[x]$)求出来 考虑到对于某种最优 ...

  3. bzoj 3242: [Noi2013]快餐店 章鱼图

    3242: [Noi2013]快餐店 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 266  Solved: 140[Submit][Status] ...

  4. bzoj3242 [Noi2013]快餐店

    Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...

  5. 3242: [Noi2013]快餐店 - BZOJ

    Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...

  6. 动态规划:NOI2013 快餐店

    Description 小 T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近 的地方. 快餐店的顾客分布 ...

  7. NOI2013 快餐店

    http://uoj.ac/problem/126 总的来说,还是很容易想的,就是有点恶心. 首先,很明显只有一个环. 我们先找出这个环,给各棵树编号id[i],然后各棵树分别以环上的点为根,求出每个 ...

  8. bzoj 3242: [Noi2013]快餐店

    Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...

  9. BZOJ3242/UOJ126 [Noi2013]快餐店

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

随机推荐

  1. 游标定位:Cursor类

    关于 Cursor Cursor 是每行的集合. 使用 moveToFirst() 定位第一行. 你必须知道每一列的名称. 你必须知道每一列的数据类型. Cursor 是一个随机的数据源. 所有的数据 ...

  2. luogu P1181 数列分段Section I x

    P1181 数列分段Section I 题目描述 对于给定的一个长度为N的正整数数列A[i],现要将其分成连续的若干段,并且每段和不超过M(可以等于M),问最少能将其分成多少段使得满足要求. 输入输出 ...

  3. codevs 5935 小球 x

    题目描述 Description 许多的小球一个一个的从一棵满二叉树上掉下来组成FBT(Full Binary Tree,满二叉树),每一时间,一个正在下降的球第一个访问的是非叶子节点.然后继续下降时 ...

  4. 搜狗微信采集 —— python爬虫系列一

    前言:一觉睡醒,发现原有的搜狗微信爬虫失效了,网上查找一翻发现10月29日搜狗微信改版了,无法通过搜索公众号名字获取对应文章了,不过通过搜索主题获取对应文章还是可以的,问题不大,开搞! 目的:获取搜狗 ...

  5. ZooKeeper设置开机启动

    1 在init.d目录下新建脚本文件 进入到/etc/rc.d/init.d目录下,命令是: cd    /etc/rc.d/init.d 新建一个名为zookeeper的文件,命令是: touch ...

  6. 一台linux机器远程mount另一台linux机器

    本机电脑系统是unbantu,要将另一台linux电脑上的文件mount到本机目录下.mount的原理是网络文件系统,即NFS,本机操作步骤如下 一,安装 nfs-common  : apt inst ...

  7. Json C#解析

    介绍 项目中数据格式如果是是Json格式,推荐大家使用LitJson和Newtonsoft.json进行解析 库的详细介绍和下载地址 推荐使用VS自带的Nuget来使用 Newtonsoft.Json ...

  8. 使用SSH和Nginx做内网HTTP映射

    https://blog.csdn.net/imdyf/article/details/80143991

  9. 【零售小程序】—— webview嵌套web端项目(原生开发支付功能)

    index → index.wxml  套webwiew // url 活动url bindmessage 接收信息 <web-view src='{{url}}' bindmessage='m ...

  10. 二、Python基础

    1.变量名 数字,字母,下划线:aaa1;aa_b1 不能以数字开头:1aa 变量名不能是python内部的关键字 2.getpass import getpass username=raw_inpu ...