P4292 [WC2010]重建计划

题目描述

\(X\)国遭受了地震的重创, 导致全国的交通近乎瘫痪,重建家园的计划迫在眉睫。\(X\)国由\(N\)个城市组成, 重建小组提出,仅需建立\(N-1\)条道路即可使得任意两个城市互相可达。于是,重建小组很快提出了一个包含\(N-1\)条道路的方案,并满足城市之间两两可达,他们还计算评估了每条道路\(e\)建设之后可以带来的价值\(v(e)\)。

由于重建计划复杂而艰难,经费也有一定限制。因此,政府要求第一期重建工程修建的道路数目为\(k\)条,但需满足\(L ≤ k ≤ U\), 即不应少于\(L\)条,但不超过\(U\)条。同时,为了最大化利用率,要求建设的这些道路恰好组成一条简单路径,即所建设的\(k\)条路径可以构成一个排列\(e_1 = (p_1, q_1), e_2 = (p_2, q_2),\dots, e_k = (p_k, q_k)\), 对于 \(1 ≤ i < k\), 有\((q_i = p_i+1)\)。

重建小组打算修改他们的原有方案以满足要求,即在原有的N-1条道路中寻找一条路径S作为新的方案,使得新方案中的道路平均价值

\[AvgValue = \frac{\sum _{e \in S} v(e)}{|S|}
\]

最大。这里\(v(e)\)表示道路\(e\)的价值,\(|S|\)表示新方案中道路的条数。请你帮助重建小组寻找一个最优方案。 注: 在本题中\(L\)和\(U\)的设置将保证有解。

输入输出格式

输入格式:

第一行包含一个正整数\(N\),表示\(X\)国的城市个数。

第二行包含两个正整数\(L\)、\(U\),表示政府要求的第一期重建方案中修建道路数的上下限。

接下来的\(N-1\)行描述重建小组的原有方案,每行三个正整数\(a_i, b_i, v_i\),分别表示道路\((a_i, b_i)\),其价值为\(v_i\)。其中城市由\(1\dots N\)标号。

输出格式:

仅包含一行,为一个实数\(AvgValue\),即最大平均价值。

小数点后保留三位。

说明

对于\(20\%\)的数据,\(N ≤ 5 000\);

另有\(30\%\)的数据,\(N ≤ 100 000\), 原有方案恰好为一条路径(链);

对于\(100\%\)的数据,\(N ≤ 100 000, 1 ≤ L ≤ U ≤ N-1, v_i ≤ 10^6\)。


鉴于本辣鸡代码写的天昏地暗,把自己恶心的不行,所以思路也懒得好好说了,简单说一下吧。

分数规划+线段树维护长链剖分

二分之后需要找一条长度为\([l,r]\)之间的链的边权和大于\(0\)

显然可以\(O(n^2)\)进行\(dp\),然后使用长链剖分继承重儿子。

发现继承重儿子的过程需要开一个线段树维护。

只开一个线段树维护\(dfs\)序,然后就可以很方便的进行偏移,加连接重儿子的边时可以直接区间打\(tag\)


Code:

// luogu-judger-enable-o2
#include <cstdio>
#include <algorithm>
const int N=1e5+10;
int head[N],to[N<<1],Next[N<<1],cnt;
double edge[N<<1];
void add(int u,int v,double w)
{
to[++cnt]=v,Next[cnt]=head[u],edge[cnt]=w,head[u]=cnt;
}
double tag[N<<2],mx[N<<2];
int n,lp,rp;
using std::min;
using std::max;
#define ls id<<1
#define rs id<<1|1
void pushdown(int id)
{
if(tag[id]<-1e17) return;
if(mx[ls]<-1e17) mx[ls]=tag[id];
else mx[ls]+=tag[id];
if(mx[rs]<-1e17) mx[rs]=tag[id];
else mx[rs]+=tag[id];
if(tag[ls]<-1e17) tag[ls]=tag[id];
else tag[ls]+=tag[id];
if(tag[rs]<-1e17) tag[rs]=tag[id];
else tag[rs]+=tag[id];
tag[id]=-1e18;
}
double query(int id,int L,int R,int l,int r)
{
if(L==l&&R==r) return mx[id];
pushdown(id);
int Mid=L+R>>1;
if(r<=Mid) return query(ls,L,Mid,l,r);
else if(l>Mid) return query(rs,Mid+1,R,l,r);
else return max(query(ls,L,Mid,l,Mid),query(rs,Mid+1,R,Mid+1,r));
}
void change(int id,int L,int R,int l,int r,double d)
{
if(L==l&&R==r)
{
if(mx[id]<-1e17) mx[id]=d;
else mx[id]+=d;
if(tag[id]<-1e17) tag[id]=d;
else tag[id]+=d;
return;
}
pushdown(id);
int Mid=L+R>>1;
if(r<=Mid) change(ls,L,Mid,l,r,d);
else if(l>Mid) change(rs,Mid+1,R,l,r,d);
else change(ls,L,Mid,l,Mid,d),change(rs,Mid+1,R,Mid+1,r,d);
mx[id]=max(mx[ls],mx[rs]);
}
void modify(int id,int l,int r,int p,double d)
{
if(l==r) {mx[id]=max(mx[id],d);return;}
pushdown(id);
int mid=l+r>>1;
if(p<=mid) modify(ls,l,mid,p,d);
else modify(rs,mid+1,r,p,d);
mx[id]=max(mx[ls],mx[rs]);
}
int dis[N],ws[N],dfn[N],dfsclock;
double ans;
void dfsinit(int now,int fa)
{
for(int v,i=head[now];i;i=Next[i])
if((v=to[i])!=fa)
{
dfsinit(v,now);
if(dis[to[ws[now]]]<dis[v]) ws[now]=i;
}
dis[now]=dis[to[ws[now]]]+1;
}
int tn,ty;
void dfsseg(int id,int L,int R,int l,int r,int p)
{
if(L==R)
{
int len=l+1-tn;
if(ty) modify(1,1,n,len+dfn[p],mx[id]);
else if(len+dis[p]-1>=lp&&len<rp)
ans=max(ans,mx[id]+query(1,1,n,max(dfn[p]+1,dfn[p]+lp-len),min(dfn[p]+rp-len,dfn[p]+dis[p]-1)));
return;
}
pushdown(id);
int Mid=L+R>>1;
if(r<=Mid) dfsseg(ls,L,Mid,l,r,p);
else if(l>Mid) dfsseg(rs,Mid+1,R,l,r,p);
else dfsseg(ls,L,Mid,l,Mid,p),dfsseg(rs,Mid+1,R,Mid+1,r,p);
}
void dfs(int now,int fa)
{
dfn[now]=++dfsclock;
if(ws[now])
{
dfs(to[ws[now]],now);
change(1,1,n,dfn[now]+1,dfn[now]+1,edge[ws[now]]);
if(dis[now]>2)
change(1,1,n,dfn[now]+2,dfn[now]+dis[now]-1,edge[ws[now]]);
}
for(int v,i=head[now];i;i=Next[i])
if((v=to[i])!=fa&&i!=ws[now])
{
dfs(v,now);tn=dfn[v];
change(1,1,n,dfn[v],dfn[v]+dis[v]-1,edge[i]);
ty=0,dfsseg(1,1,n,dfn[v],dfn[v]+dis[v]-1,now);
ty=1,dfsseg(1,1,n,dfn[v],dfn[v]+dis[v]-1,now);
}
if(dis[now]-1>=lp)
ans=max(ans,query(1,1,n,dfn[now]+lp,min(dfn[now]+rp,dfn[now]+dis[now]-1)));
}
bool check(double d)
{
for(int i=1;i<=cnt;i++) edge[i]-=d;
for(int i=1;i<=n<<2;i++) mx[i]=tag[i]=-1e18;
dfsclock=0,ans=-1e18;dfs(1,0);
for(int i=1;i<=cnt;i++) edge[i]+=d;
return ans>=0;
}
int main()
{
scanf("%d%d%d",&n,&lp,&rp);
double l=1e18,r=-1e18,w;
for(int u,v,i=1;i<n;i++)
{
scanf("%d%d%lf",&u,&v,&w),add(u,v,w),add(v,u,w);
l=min(l,w),r=max(r,w);
}
dfsinit(1,0);
while(l+1e-4<r)
{
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%.3lf\n",l);
return 0;
}

2018.12.14

洛谷 P4292 [WC2010]重建计划 解题报告的更多相关文章

  1. 洛谷 P4292 - [WC2010]重建计划(长链剖分+线段树)

    题面传送门 我!竟!然!独!立!A!C!了!这!道!题!incredible! 首先看到这类最大化某个分式的题目,可以套路地想到分数规划,考虑二分答案 \(mid\) 并检验是否存在合法的 \(S\) ...

  2. NOIP2015 D2T3 洛谷2680 BZOJ4326 运输计划 解题报告

    前言:个人认为这是历年NOIP中比较简单的最后一题了,因此将自己的思路与大家分享. 题目大意: 给一棵无根树,给出m条路径.允许将树上的一条边的权值改为0.求m条路径长度最大值的最小值.n,m< ...

  3. 洛谷_Cx的故事_解题报告_第四题70

    1.并查集求最小生成树 Code: #include <stdio.h> #include <stdlib.h>   struct node {     long x,y,c; ...

  4. 洛谷 P2317 [HNOI2005]星际贸易 解题报告

    P2317 [HNOI2005]星际贸易 题目描述 输入输出格式 输入格式: 输出格式: 如果可以找到这样的方案,那么输出文件output.txt中包含两个整数X和Y.X表示贸易额,Y表示净利润并且两 ...

  5. 洛谷 P3802 小魔女帕琪 解题报告

    P3802 小魔女帕琪 题目背景 从前有一个聪明的小魔女帕琪,兴趣是狩猎吸血鬼. 帕琪能熟练使用七种属性(金.木.水.火.土.日.月)的魔法,除了能使用这么多种属性魔法外,她还能将两种以上属性组合,从 ...

  6. 洛谷 P2606 [ZJOI2010]排列计数 解题报告

    P2606 [ZJOI2010]排列计数 题目描述 称一个\(1,2,...,N\)的排列\(P_1,P_2...,P_n\)是\(Magic\)的,当且仅当对所以的\(2<=i<=N\) ...

  7. 洛谷1303 A*B Problem 解题报告

    洛谷1303 A*B Problem 本题地址:http://www.luogu.org/problem/show?pid=1303 题目描述 求两数的积. 输入输出格式 输入格式: 两个数 输出格式 ...

  8. BZOJ 1758 / Luogu P4292 [WC2010]重建计划 (分数规划(二分/迭代) + 长链剖分/点分治)

    题意 自己看. 分析 求这个平均值的最大值就是分数规划,二分一下就变成了求一条长度在[L,R]内路径的权值和最大.有淀粉质的做法但是我没写,感觉常数会很大.这道题可以用长链剖分做. 先对树长链剖分. ...

  9. 洛谷 P3084 [USACO13OPEN]照片Photo 解题报告

    [USACO13OPEN]照片Photo 题目描述 农夫约翰决定给站在一条线上的\(N(1 \le N \le 200,000)\)头奶牛制作一张全家福照片,\(N\)头奶牛编号\(1\)到\(N\) ...

随机推荐

  1. python包管理工具pip

    你可以使用一个名为 pip 的程序来安装.升级和移除软件包.默认情况下 pip 将从 Python Package Index <https://pypi.org> 安装软件包.你可以在浏 ...

  2. 基于Vue的简单通用分页组件

    分页组件是每一个系统里必不可少的一个组件,分页组件分为两部分.第一部分是模版部分,用于显示当前分页组件的状态,例如正在获取数据.没有数据.没有下一页等等:第二部分是分页数据对象,用于封装一个分页组件的 ...

  3. SQL Server 各版本安装包分享

    已将SQL Server 2005以上各版本的安装包分享到百度云盘,有需要的朋友可以下载进行安装,相关安装教程可以百度搜索.安装遇到难以解决的问题可以留言给我,2016版以上在选择功能的时候建议初学者 ...

  4. HIVE函数的UDF、UDAF、UDTF

    一.词义解析 UDF(User-Defined-Function) 一进一出 UDAF(User- Defined Aggregation Funcation) 多进一出 (聚合函数,MR) UDTF ...

  5. QRCode 二维码

    一.生成二维码 1.二维码就是绘制成黑白相间的图片,所谓的黑白相间就是代表0和1 ,二维码大约可以容纳500多个中文,所以用途之广显而易见. 所需的jar包  http://pan.baidu.com ...

  6. 笔试题——C++开发简单记录错误模块

    题目:链接:https://www.nowcoder.com/questionTerminal/67df1d7889cf4c529576383c2e647c48 来源:牛客网 解析及代码来源:http ...

  7. import 导入包的特别用法总结

    指定别名 可以为包指定一个别名,以便记忆或提高输入效率 如 import str "strings" 在使用的时候可以直接使用别名,如原先要写成strings.Contains,现 ...

  8. [T-ARA][느낌 아니까][懂得那份感觉]

    歌词来源:http://music.163.com/#/song?id=27808771 作曲 : 박덕상/박현중 [作曲 : p/bag-ddeog-ssang-/p/ba-Kyeon-c/jung ...

  9. R软件中 文本分析安装包 Rjava 和 Rwordseg 傻瓜式安装方法四部曲

    这两天,由于要做一个文本分析的内容,所以搜索了一天R语言中的可以做文本分析的加载包,但是在安装包的过程,真是被虐千百遍,总是安装不成功.特此专门写一篇博文,把整个心塞史畅快的释放一下. ------- ...

  10. Python图形界面开发—wxPython库的布局管理及页面切换

    前言 wxPython是基于Python的跨平台GUI扩展库,对wxWidgets( C++ 编写)封装实现.GUI程序的开发中界面布局是很重要的一个部分,合理的页面布局能够给予用户良好使用体验.虽然 ...