【BZOJ 3242】 (环套树、线段树+树形DP?)
3242: [Noi2013]快餐店
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 728 Solved: 390Description
小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 1Sample Output
2.0HINT
数据范围
对于 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?)的更多相关文章
- Bzoj 2752 高速公路 (期望,线段树)
Bzoj 2752 高速公路 (期望,线段树) 题目链接 这道题显然求边,因为题目是一条链,所以直接采用把边编上号.看成序列即可 \(1\)与\(2\)号点的边连得是. 编号为\(1\)的点.查询的时 ...
- 浅谈树套树(线段树套平衡树)&学习笔记
0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...
- bzoj 4871: [Shoi2017]摧毁“树状图” [树形DP]
4871: [Shoi2017]摧毁"树状图" 题意:一颗无向树,选两条边不重复的路径,删去选择的点和路径剩下一些cc,求最多cc数. update 5.1 : 刚刚发现bzoj上 ...
- BZOJ1758[Wc2010]重建计划——分数规划+长链剖分+线段树+二分答案+树形DP
题目描述 输入 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai, ...
- 【bzoj5123】[Lydsy12月赛]线段树的匹配 树形dp+记忆化搜索
题目描述 求一棵 $[1,n]$ 的线段树的最大匹配数目与方案数. $n\le 10^{18}$ 题解 树形dp+记忆化搜索 设 $f[l][r]$ 表示根节点为 $[l,r]$ 的线段树,匹配选择根 ...
- CF700E Cool Slogans SAM、线段树合并、树形DP
传送门 在最优的情况下,序列\(s_1,s_2,...,s_k\)中,\(s_i (i \in [2 , k])\)一定会是\(s_{i-1}\)的一个\(border\),即\(s_i\)同时是\( ...
- BZOJ 4422 Cow Confinement (线段树、DP、扫描线、差分)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4422 我真服了..这题我能调一天半,最后还是对拍拍出来的...脑子还是有病啊 题解: ...
- 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分
树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...
- BZOJ 3779: 重组病毒(线段树+lct+树剖)
题面 escription 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病 ...
- 2014 Super Training #9 E Destroy --树的直径+树形DP
原题: ZOJ 3684 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3684 题意: 给你一棵树,树的根是树的中心(到其 ...
随机推荐
- Elasticsearch技术解析与实战(七)Elasticsearch批量操作
批量查询 1.如果查询的document是不同index下的不同type种的话 GET /_mget { "docs" : [ { "_index" : &qu ...
- powerdesigner怎么设置同时显示name和code
实现方法:Tools-Display Preference 从数据库里抽取了数据模型,为了理清思路,需要将name改为中文名称,但是pd自动将name填充为code,可以通过如下配置修改: 选择too ...
- 用create-react-app来快速配置react
最近在学react,然后感觉自己之前用的express+gulp+webpack+ejs的工作环境还是基于html+js+css这种三层架构的应用,完全跟react不是一回事. 愚蠢的我居然在原先的这 ...
- TypeScript在node项目中的实践
TypeScript在node项目中的实践 TypeScript可以理解为是JavaScript的一个超集,也就是说涵盖了所有JavaScript的功能,并在之上有着自己独特的语法.最近的一个新项目开 ...
- 面试中关于Java虚拟机(jvm)的问题看这篇就够了
最近看书的过程中整理了一些面试题,面试题以及答案都在我的文章中有所提到,希望你能在以问题为导向的过程中掌握虚拟机的核心知识.面试毕竟是面试,核心知识我们还是要掌握的,加油~~~ 下面是按jvm虚拟机知 ...
- java反序列化漏洞
http://www.freebuf.com/vuls/86566.html 有时间了 仔细阅读
- 64_m3
molequeue-doc-0.8.0-2.20161222giteb397e.fc26.no..> 05-Apr-2017 10:04 451570 molequeue-libs-0.8.0- ...
- rabbitmq集群搭建方法简介(测试机linux centos)【转】
本文将介绍四台机器搭建rabbitmq集群: rabbitmq IP和主机名(每台机器已安装RabbitMQ 3.5.6, Erlang 18.1) 192.168.87.73 localhost73 ...
- LAMP结合discuz论坛的配置
一.安装discuz ---->//download discuz; [root@localhost ~]# mkdir /data/www [root@localhost ~]# cd /da ...
- 当array_filter函数的callback留空时 他会过滤掉所有键值为false的键
当array_filter函数的callback留空时 他会过滤掉所有键值为false的键