3242: [Noi2013]快餐店

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 728  Solved: 390

Description

小T打算在城市C开设一家外送快餐店。送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方。 快餐店的顾客分布在城市C的N 个建筑中,这N 个建筑通过恰好N 条双向道路连接起来,不存在任何两条道路连接了相同的两个建筑。任意两个建筑之间至少存在一条由双向道路连接而成的路径。小T的快餐店可以开设在任一建筑中,也可以开设在任意一条道路的某个位置上(该位置与道路两端的建筑的距离不一定是整数)。 现给定城市C的地图(道路分布及其长度),请找出最佳的快餐店选址,输出其与最远的顾客之间的距离。

Input

第一行包含一个整数N,表示城市C中的建筑和道路数目。
接下来N行,每行3个整数,Ai,Bi,Li(1≤i≤N;Li>0),表示一条道路连接了建筑Ai与Bi,其长度为Li 。

Output

仅包含一个实数,四舍五入保留恰好一位小数,表示最佳快餐店选址距离最远用户的距离。
注意:你的结果必须恰好有一位小数,小数位数不正确不得分。

Sample Input

1 2 1
1 4 2
1 3 2
2 4 1

Sample Output

2.0

HINT

数据范围

对于 10%的数据,N<=80,Li=1;

对于 30%的数据,N<=600,Li<=100;

对于 60% 的数据,N<=2000,Li<=10^9;

对于 100% 的数据,N<=10^5,Li<=10^9

Source

【分析】

  这题好难啊。。

  首先是,显然求的是树上的最长链。但是这是一个环套树。

  对于基环树上的点,求出他们两两间的最长链,这个用树形DP,其实dfs一遍就好了。

  当然也是可以走环的,如果走环的话,环可以走两边,肯定选了最近的一边走了。这个最长链一定是断掉环的某边之后那棵树的最长链。

  所以可以枚举断掉环上某条边。问现在的最长链,取最优那个即可。

  这个怎么做呢?

  求出f[i]表示i是环上一点,他的基环树向下的最长链是f[i]。

  假设断掉了某条边,环变成了链,那么记录一个sm[i]表示到左端点的距离

  对于环上两点i,j,则最长链有sm[j]-sm[i]+f[i]+f[j]=(f[i]-sum[i])+(sm[j]+f[j])

  就是维护两个东西,f[i]-sum[i]和f[i]+sm[i],选两个最大的加起来。

  但是这两个最大的不能是同一个id,所以还要维护次大值。

  当你枚举另一条断边的时候,只要修改一个sm值就好了。

  【一开始LL没开,INF太小哭。。【然后一生气又全开LL了ORZ

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define Maxn 100010
// #define INF 0x7fffffff
#define LL long long
const LL INF=1LL<<; LL mymax(LL x,LL y) {return x>y?x:y;}
LL mymin(LL x,LL y) {return x<y?x:y;} LL n,r1[Maxn],r2[Maxn],rr[Maxn],nc[Maxn];
LL cc[Maxn]; struct node
{
LL x,y,c,next;
}t[Maxn*];
LL first[Maxn],len;
LL fa[Maxn]; LL ffa(LL x)
{
if(fa[x]!=x) fa[x]=ffa(fa[x]);
return fa[x];
} void ins(LL x,LL y,LL c)
{
t[++len].x=x;t[len].y=y;t[len].c=c;
t[len].next=first[x];first[x]=len;
} LL cr[Maxn]; bool dfs(LL x,LL ff,LL nw)
{
if(x==r2[nw]) {cr[++cr[]]=x;cc[cr[]]=nc[nw];return ;}
for(LL i=first[x];i;i=t[i].next) if(t[i].y!=ff)
{
if(dfs(t[i].y,x,nw)) {cr[++cr[]]=x;cc[cr[]]=t[i].c;return ;}
}
return ;
} bool vis[Maxn];
LL ln[Maxn]; struct nnode
{
LL l,r,lc,rc;
LL mx1,mx2,m1,m2,id1,id2;
}tr[Maxn*]; void upd(LL x)
{
LL lc=tr[x].lc,rc=tr[x].rc;
tr[x].mx1=mymax(tr[lc].mx1,tr[rc].mx1);
tr[x].id1=tr[lc].mx1>tr[rc].mx1?tr[lc].id1:tr[rc].id1;
tr[x].mx2=tr[lc].mx1>tr[rc].mx1?mymax(tr[lc].mx2,tr[rc].mx1):mymax(tr[lc].mx1,tr[rc].mx2); tr[x].m1=mymax(tr[lc].m1,tr[rc].m1);
tr[x].id2=tr[lc].m1>tr[rc].m1?tr[lc].id2:tr[rc].id2;
tr[x].m2=tr[lc].m1>tr[rc].m1?mymax(tr[lc].m2,tr[rc].m1):mymax(tr[lc].m1,tr[rc].m2);
} LL tot=,sm[Maxn];
LL build(LL l,LL r,LL nw)
{
LL x=++tot;
tr[x].l=l;tr[x].r=r;
if(l==r)
{
LL id=l+rr[nw-];
tr[x].mx1=ln[cr[id]]+sm[id];tr[x].mx2=-INF;
tr[x].m1=ln[cr[id]]-sm[id];tr[x].m2=-INF;
tr[x].id1=tr[x].id2=l;
tr[x].lc=tr[x].rc=;
}
else
{
LL mid=(l+r)>>;
tr[x].lc=build(l,mid,nw);
tr[x].rc=build(mid+,r,nw);
upd(x);
}
return x;
} LL g[Maxn];
void get_l(LL x,LL ff)
{
ln[x]=;LL mx1=,mx2=;
g[x]=;
for(LL i=first[x];i;i=t[i].next) if(t[i].y!=ff&&vis[t[i].y])
{
LL y=t[i].y;
get_l(y,x);
if(ln[y]+t[i].c>mx1) mx2=mx1,mx1=ln[y]+t[i].c;
else if(ln[y]+t[i].c>mx2) mx2=ln[y]+t[i].c;
g[x]=mymax(g[x],g[y]);
}
g[x]=mymax(g[x],mx1+mx2);
ln[x]=mx1;
} void change(LL x,LL y,LL nw)
{
if(tr[x].l==tr[x].r)
{
LL id=y+rr[nw-];
tr[x].mx1=sm[id]+ln[cr[id]];
tr[x].m1=ln[cr[id]]-sm[id];
return;
}
LL mid=(tr[x].l+tr[x].r)>>;
if(y<=mid) change(tr[x].lc,y,nw);
else change(tr[x].rc,y,nw);
upd(x);
} LL get_ans()
{
if(tr[].id1!=tr[].id2) return tr[].mx1+tr[].m1;
else return mymax(tr[].mx1+tr[].m2,tr[].mx2+tr[].m1);
} int main()
{
scanf("%lld",&n);
len=;
for(LL i=;i<=n;i++) fa[i]=i;
LL cnt=;
for(LL i=;i<=n;i++)
{
LL x,y,c;
scanf("%lld%lld%lld",&x,&y,&c);
if(ffa(x)==ffa(y))
{
r1[++cnt]=x;r2[cnt]=y;
nc[cnt]=c;
}
else
{
fa[ffa(x)]=ffa(y);
ins(x,y,c);ins(y,x,c);
} }
cr[]=;rr[]=;
for(LL i=;i<=cnt;i++)
{
dfs(r1[i],,i);
rr[i]=rr[i-]+cr[];
}
memset(vis,,sizeof(vis));
for(LL i=;i<=cr[];i++) vis[cr[i]]=;
LL ans=;
for(LL i=;i<=cr[];i++)
{
get_l(cr[i],);
ans=mymax(ans,g[cr[i]]);
}
for(LL i=;i<=cnt;i++)
{
sm[rr[i-]+]=;
LL mn=INF; for(LL j=rr[i-]+;j<=rr[i];j++) sm[j]=sm[j-]+cc[j]; build(,rr[i]-rr[i-],i);
mn=mymin(mn,get_ans());
for(LL j=rr[i-]+;j<rr[i];j++)
{
LL p=j,q=p-;
if(j==rr[i-]+) q=rr[i];
sm[p]=sm[q]+cc[p]; change(,p-rr[i-],i);
mn=mymin(mn,get_ans());
}
ans=mymax(ans,mn);
}
printf("%.1lf\n",ans*1.0/);
return ;
}

2017-03-25 11:57:32

【BZOJ 3242】 (环套树、线段树+树形DP?)的更多相关文章

  1. Bzoj 2752 高速公路 (期望,线段树)

    Bzoj 2752 高速公路 (期望,线段树) 题目链接 这道题显然求边,因为题目是一条链,所以直接采用把边编上号.看成序列即可 \(1\)与\(2\)号点的边连得是. 编号为\(1\)的点.查询的时 ...

  2. 浅谈树套树(线段树套平衡树)&学习笔记

    0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...

  3. bzoj 4871: [Shoi2017]摧毁“树状图” [树形DP]

    4871: [Shoi2017]摧毁"树状图" 题意:一颗无向树,选两条边不重复的路径,删去选择的点和路径剩下一些cc,求最多cc数. update 5.1 : 刚刚发现bzoj上 ...

  4. BZOJ1758[Wc2010]重建计划——分数规划+长链剖分+线段树+二分答案+树形DP

    题目描述 输入 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai, ...

  5. 【bzoj5123】[Lydsy12月赛]线段树的匹配 树形dp+记忆化搜索

    题目描述 求一棵 $[1,n]$ 的线段树的最大匹配数目与方案数. $n\le 10^{18}$ 题解 树形dp+记忆化搜索 设 $f[l][r]$ 表示根节点为 $[l,r]$ 的线段树,匹配选择根 ...

  6. CF700E Cool Slogans SAM、线段树合并、树形DP

    传送门 在最优的情况下,序列\(s_1,s_2,...,s_k\)中,\(s_i (i \in [2 , k])\)一定会是\(s_{i-1}\)的一个\(border\),即\(s_i\)同时是\( ...

  7. BZOJ 4422 Cow Confinement (线段树、DP、扫描线、差分)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4422 我真服了..这题我能调一天半,最后还是对拍拍出来的...脑子还是有病啊 题解: ...

  8. 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分

    树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...

  9. BZOJ 3779: 重组病毒(线段树+lct+树剖)

    题面 escription 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病 ...

  10. 2014 Super Training #9 E Destroy --树的直径+树形DP

    原题: ZOJ 3684 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3684 题意: 给你一棵树,树的根是树的中心(到其 ...

随机推荐

  1. 新手应知道的ASP.NET代码编写规范

    1.局部变量的名称要有意义,尽量用对应的英文命名,比如“用户姓名”变量,不要用aa bb cc等来命名,而要使用userName. 2.不要使用单个字母的变量,如i.n.x等.而要使用index.te ...

  2. Let's Encrypt 免费通配 https 签名证书 安装方法2 ,安卓签名无法认证!

    Let's Encrypt 免费通配 https 签名证书 安装方法 按照上文 配置完毕后你会发现 在pc浏览器中正常访问,在手机浏览器中无法认证 你只需要安装一个或多个中级证书 1.查看Nginx ...

  3. hihoCoder 1174 : 拓扑排序·一

    题目链接:http://hihocoder.com/problemset/problem/1174 题目是中文题面我就不说题意了,要看题面的请点击上方链接~ 代码实现如下: #include < ...

  4. 从docker到docker-compose部署一个nginx+flask+mysql+redis应用

    目的是把一个flask项目的mysql数据库.redis数据库.flask应用.nginx服务分别装到四个容器中,然后用docker-compose命令同时启动与关闭 一.安装docker Docke ...

  5. MSSQL 详解SQL Server连接(内连接、外连接、交叉连接)

    在查询多个表时,我们经常会用“连接查询”.连接是关系数据库模型的主要特点,也是它区别于其它类型数据库管理系统的一个标志. 什么是连接查询呢? 概念:根据两个表或多个表的列之间的关系,从这些表中查询数据 ...

  6. Mac最新系统bssdb BUG

    这个bug在Mac OS更新到10.14时候出现,当前系统版本 ➜ git:(master) sw_vers ProductName: Mac OS X ProductVersion: 10.14 B ...

  7. Linux-Load Average解析(转)

    load Average 1.1:什么是Load?什么是Load Average?   Load 就是对计算机干活多少的度量(WikiPedia:the system Load is a measur ...

  8. .Net Core 部署到 CentOS7 64 位系统中的步骤

    建议使用 root 管理员账户操作 1.安装工具 1.apache 2..Net Core(dotnet-sdk-2.0) 3.Supervisor(进程管理工具,目的是服务器一开机就启动服务器 上发 ...

  9. UFLDL 教程学习笔记(六)主成分分析

    教程:http://ufldl.stanford.edu/tutorial/supervised/MultiLayerNeuralNetworks/ 以及这篇博文,写的很清楚:http://blog. ...

  10. 【ios开发之疑难杂症】xcode运行出现SpringBoard 无法启动应用程序(错误:7)

    问题:xcode运行出现SpringBoard 无法启动应用程序(错误:7) 解决方案: 重启模拟器