题目大意

给定一棵有nn个节点的点带权(viv_i)无根树。你需要选择一些互不相交(包括端点)的路径。如果你选择了kk条路径,且覆盖的点权和为SS,得分就为Sk+1\frac S{k+1}。
另外,在选取路径之前,你必须执行一次如下的操作(操作分为三个步骤):

  1. 选定整数参数CC,满足C∈[0,T]C\in[0,T]
  2. 将所有点权加上CC
  3. 将所有点权对LIMITLIMIT取模。

其中TT,LIMITLIMIT的值已经被给出,你需要求出可能的最大得分。

1≤n≤5×103,vi,t<LIMIT≤1051\le n\le5\times10^3,v_i,t\lt LIMIT\le10^5


题目分析

先不考虑必须要执行的操作,假设我知道每一个点的权值,怎么做呢?
分数规划的常见套路:考虑二分答案ansans,那么当前答案可行当且仅当存在方案满足:

Sk+1>ans

\frac{S}{k+1}>ans

S−k×ans>ans]

S-k\times ans>ans ]
那么怎么判断当前答案是否可行呢?可以发现,如果我们在计算时将每一条路径各自带来的得分都减去 ansans,那么左边式子是可以看成与路径条数 kk无关的。
因此我们使用动态规划算法来判定答案是否可行。我们随便选一个根节点,设fif_i和 gig_i分别表示节点 ii向上延伸/不向上延伸(包括它作为两个儿子向上延伸的交点和不选它两种情况),子树ii的最大得分。
这个瞎讨论一下就可以转移,时间复杂度是 O(n)\mathrm O(n)的。也就是说我们可以在线性时间内完成对答案可行性的判定。
那么现在要考虑执行操作,显然我们没有必要对于 [0,T][0,T]内的每一个数都考察一遍,因为如果有很多个 CC,它们都不会造成任何一个viv_i被 LIMITLIMIT模掉,那么显然这些 CC中最大那个会造成更优的结果。因此我们只用考察LIMIT−vi−1LIMIT-v_i-1这种数(当然还要判断是否小于等于 TT之类的)。令EE表示二分答案次数,现在时间复杂度是 O(n2E)\mathrm O(n^2E)。
这让还不能得到所有分数,怎么办呢?
在这题,我们可以线性判断对于一个点权序列,一个答案是否可行,但是要具体求出对于这个点权序列的最优解,就要算上二分的复杂度。
那么我们考虑加上一个优化,每次二分之前,先判定对于当前要考察的点权序列,目前的最优解是否可行,如果不可行,那么在这个点权序列我们不可能计算出更加优的结果,就不用在这里二分了。
但是这样我依然有可能每次都要二分,毕竟有可能很不好运,每一个考察值的答案都比前一个优。那怎么办?我们随机化!
将所有考察值去重,然后随机打乱,使用上面的方法判断。这样期望只会有 logn\log n个值要进行二分。这个证明需要用到一下结论:

  • 一个nn个数随机顺序的排列,我们从第一个数开始,每次跳到后面第一个比自己大的位置,期望情况下需要logn\log n步。
  • 证明:根据期望的线性性,我们只要计算出每一个位置对步数造成贡献的概率之和。显然一个位置ii对答案造成贡献当且仅当在它前面没有更大的数,这个概率为1i\frac 1 i,我们累加起来就是调和级数,是O(logn)\mathrm O(\log n)的。

于是这里的时间复杂度变为O(n2+nElogn)\mathrm O(n^2+nE\log n)了。


代码实现

请注意代码常数……

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>using namespace std;typedef double db;const db EPS=1e-8;
const db INF=1e+40;
const int N=5005;
const int E=N<<1;int c[N],v[N],last[N];
int nxt[E],tov[E];
int n,T,LIM,tot,m;
db f[N],g[N];
db ans,sum;void insert(int x,int y){tov[++tot]=y,nxt[tot]=last[x],last[x]=tot;}void dfs(int x,int fa,db cur)
{f[x]=-cur,g[x]=0.0;db d1=-INF,d2=-INF,gsum=0.0;for (int i=last[x],y;i;i=nxt[i])if ((y=tov[i])!=fa){dfs(y,x,cur);gsum+=g[y];if (d1<f[y]-g[y]) d2=d1,d1=f[y]-g[y];else if (d2<f[y]-g[y]) d2=f[y]-g[y];}f[x]=max(f[x],d1)+gsum+v[x];g[x]=max(g[x],max(d1+d2+cur+v[x],d1+v[x]))+gsum;
}bool judge(db cur)
{dfs(1,0,cur);return max(f[1],g[1])>=cur;
}db calc(db l,db r)
{db mid,ret=l;for (;r-l>=EPS;){mid=(l+r)/2.0;if (judge(mid)) l=(ret=mid)+EPS;else r=mid-EPS;}return ret;
}void solve()
{ans=0.0;for (int i=1;i<=m;i++){for (int j=1;j<=n;j++) v[j]+=c[i],v[j]>=LIM?v[j]-=LIM:0;if (judge(ans)) ans=calc(ans,sum);for (int j=1;j<=n;j++) v[j]-=c[i],v[j]<0?v[j]+=LIM:0;}
}int main()
{srand(time(0));freopen("tree.in","r",stdin),freopen("tree.out","w",stdout);scanf("%d%d",&n,&LIM);for (int i=1;i<=n;i++) scanf("%d",&v[i]),sum+=v[i]+LIM;for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),insert(x,y),insert(y,x);scanf("%d",&T);for (int i=1;i<=n;i++) c[i]=min(T,LIM-1-v[i]);sort(c+1,c+1+n);m=0;for (int i=1;i<=n;i++) if (i==1||c[i]!=c[m]) c[++m]=c[i];random_shuffle(c+1,c+1+m);solve();printf("%.6lf\n",ans);fclose(stdin),fclose(stdout);return 0;
}

[JZOJ3987]Tree相关推荐

  1. 107. Binary Tree Level Order Traversal II

    题目 Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from l ...

  2. 102. Binary Tree Level Order Traversal

    题目 Binary Tree Level Order Traversal 层次遍历二叉树 链接 Given a binary tree, return the level order traversa ...

  3. Python---哈夫曼树---Huffman Tree

    今天要讲的是天才哈夫曼的哈夫曼编码,这是树形数据结构的一个典型应用. !!!敲黑板!!!哈夫曼树的构建以及编码方式将是我们的学习重点. 老方式,代码+解释,手把手教你Python完成哈夫曼编码的全过程 ...

  4. [Java]LeetCode297. 二叉树的序列化与反序列化 | Serialize and Deserialize Binary Tree

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblog ...

  5. Code Forces Bear and Forgotten Tree 3 639B

    B. Bear and Forgotten Tree 3 time limit per test2 seconds memory limit per test256 megabytes inputst ...

  6. Codeforces Round #417:E. FountainsSagheer and Apple Tree(树上博弈)

    Codeforces Round #417:E. FountainsSagheer and Apple Tree(树上博弈) 标签: codeforces 2017-06-02 11:41 29人阅读 ...

  7. datagrid底部显示水平滚动_DevExpress WPF v19.1:Data Grid/Tree List等控件功能增强

    行业领先的.NET界面控件DevExpress 日前正式发布v19.1版本,本站将以连载的形式介绍各版本新增内容.在本系列文章中将为大家介绍DevExpress WPF v19.1中新增的一些控件及部 ...

  8. java easyui tree例子_EasyUI Tree的简单使用

    此前写过zTree插件的demo,没有记录下来,这次记录一下EasyUI的Tree. 实现效果:获取数据库表的数据,以树结构的形式展示出来. 树结构数据分为同步加载和异步加载,同步加载就是初始化加载时 ...

  9. windows用 tree命令查看目录文件夹结构

    windows用 tree命令查看目录文件夹结构 ## 查看帮助 tree --helptree --dirsfirst --filelimit 6 -h -t –dirsfirst 目录优先展示 – ...

  10. PCL :K-d tree 2 结构理解

    K-d tree 基础思路:(先看之前的KNN思想,更容易理解) 导语:kd 树是一种二叉树数据结构,可以用来进行高效的 kNN 计算.kd 树算法偏于复杂,本篇将先介绍以二叉树的形式来记录和索引空间 ...

最新文章

  1. Kotlin 在kotlin内使用Java的一些注意(长篇)
  2. TreeView查获节点并选中节点
  3. Object-c基础之一:#import,NSLog(),数据类型
  4. .net如何引用该命名空间
  5. oracle数据恢复
  6. Python_Python处理JSON文件
  7. atitit.印度教与java宗教的特点与观念对比 attilax总结
  8. APP抓包之fiddler使用介绍
  9. 2018-8-10-git-push-错误-hook-declined-
  10. python四分位数_四分位数计算过程
  11. C语言的进制转换以及算法实现
  12. 云词:让英语学习平步青云
  13. 【loj】#10064. 「一本通 3.1 例 1」黑暗城堡(最短路径生成树 dijkstra+Prim)
  14. python提醒事件_利用python实现短信和电话提醒功能的例子
  15. 深圳计算机专业中专学校,深圳中专学校
  16. TP50 TP90 TP95 TP99 TP999 TP9999
  17. Android 实现仿微信朋友圈全文、收起的功能
  18. Typora 是什么?
  19. XmlHttp的open( )方法
  20. linux svn 忽略指定文件

热门文章

  1. LM3886TF功放制作进展
  2. 人居一世间, 忽若风吹尘 2019.07.07.
  3. 伸缩式工具刀行业调研报告 - 市场现状分析与发展前景预测
  4. 编译Android版本的chromium浏览器
  5. burst什么意思_burst是什么意思_burst在线翻译_英语_读音_用法_例句_海词词典
  6. 百度重度依赖者谈谈恶意点击
  7. Excel中文转拼音(完整版)-转
  8. Jenkins自动集成
  9. android 音量曲线,Android音量控制曲线
  10. SAS数据导入input要点