题目链接:重建计划

  这道题现在已经成为一道板子题了……

  这是个非常显然的0-1分数规划,可以二分答案之后树分治判定一下。注意树分治的时候如果使用单调队列,需要把所有儿子预先按最大深度排好序,否则会被扫把型的数据卡到\(n^2\log n\)。

  然后跑得非常慢……于是把二分答案改成了Dinkelbach迭代法。Dinkelbach迭代法就是每次用当前最优解来更新答案的界,跑得比香港记者还快

  听说这玩意儿复杂度上界是\(\log\)级别的?然而我并不会证……感觉这玩意儿就是玄学啊……

  二分答案代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<cmath>
  6. #include<vector>
  7. #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
  8. #define maxn 100010
  9. #define INF 2147483647
  10. #define eps 1e-6
  11.  
  12. using namespace std;
  13. typedef long long llg;
  14.  
  15. int n,L,R,siz[maxn],dx[maxn],lc,dep[maxn];
  16. int fr[maxn<<1],a[maxn],la,d[maxn],ld,s[maxn];
  17. int head[maxn],next[maxn<<1],to[maxn<<1],tt;
  18. double c[maxn<<1],lt,dis[maxn];
  19. double c1[maxn],c2[maxn],ans;
  20. bool vis[maxn];
  21.  
  22. int getint(){
  23. int w=0;bool q=0;
  24. char c=getchar();
  25. while((c>'9'||c<'0')&&c!='-') c=getchar();
  26. if(c=='-') c=getchar(),q=1;
  27. while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
  28. return q?-w:w;
  29. }
  30.  
  31. bool cmp(int x,int y){return dep[to[x]]<dep[to[y]];}
  32. void link(int x,int y,int z){
  33. to[++tt]=y;next[tt]=head[x];
  34. head[x]=tt; c[tt]=z;
  35. }
  36.  
  37. void dfs(int u,int x){
  38. siz[u]=1; dx[u]=0; dep[u]=x;
  39. d[++ld]=u; vis[u]=1;
  40. for(int i=head[u],v;v=to[i],i;i=next[i])
  41. if(!vis[v]){
  42. dfs(v,x+1); siz[u]+=siz[v];
  43. dx[u]=max(dx[u],siz[v]);
  44. dep[u]=max(dep[u],dep[v]);
  45. }
  46. vis[u]=0;
  47. }
  48.  
  49. void getroot(int u,int fa){
  50. ld=0; dfs(u,0); int k=0,_k=INF;
  51. for(int l=1,i;i=d[l],l<=ld;l++){
  52. dx[i]=max(dx[i],siz[u]-siz[i]);
  53. if(dx[i]<_k) k=i,_k=dx[i];
  54. }
  55. vis[k]=1; fr[fa]=k;
  56. for(int i=head[k];i;i=next[i])
  57. if(!vis[to[i]]) getroot(to[i],i);
  58. ld=0; dfs(k,0); vis[k]=0; la=0;
  59. for(int i=head[k];i;i=next[i]) a[++la]=i;
  60. sort(a+1,a+la+1,cmp); next[a[la]]=0; head[k]=a[1];
  61. for(int i=1;i<la;i++) next[a[i]]=a[i+1];
  62. }
  63.  
  64. void getdis(int u,int de){
  65. vis[u]=1; lc=max(lc,de); c2[de]=max(c2[de],dis[u]);
  66. for(int i=head[u],v;v=to[i],i;i=next[i])
  67. if(!vis[v]) dis[v]=dis[u]+c[i],getdis(v,de+1);
  68. vis[u]=0;
  69. }
  70.  
  71. void work(int u,int fa){
  72. int k=fr[fa]; vis[k]=1; int cl=0;
  73. for(int i=head[k],v,l,r,no;v=to[i],i;i=next[i]){
  74. if(vis[v]) continue; lc=0;
  75. dis[v]=c[i]; getdis(v,1); l=r=0; no=0;
  76. for(int j=lc;j;j--){
  77. while(no<=R-j && no<=cl){
  78. while(l<r && c1[s[r-1]]<=c1[no]) r--;
  79. s[r++]=no++;
  80. }
  81. while(l<r && s[l]<L-j) l++;
  82. if(l<r) ans=max(ans,c2[j]+c1[s[l]]);
  83. if(ans+eps>=0) break;
  84. }
  85. cl=max(cl,lc);
  86. for(int j=1;j<=lc;j++) c1[j]=max(c1[j],c2[j]),c2[j]=-1e9;
  87. }
  88. for(int i=1;i<=cl;i++) c1[i]=-1e9;
  89. if(ans+eps>=0){vis[k]=0;return;}
  90. for(int i=head[k];i;i=next[i])
  91. if(!vis[to[i]]) work(to[i],i);
  92. vis[k]=0;
  93. }
  94.  
  95. bool check(double x){
  96. for(int i=1;i<=tt;i++) c[i]+=lt-x; lt=x;
  97. ans=-1e9; work(1,0); return ans+eps>=0;
  98. }
  99.  
  100. int main(){
  101. File("a");
  102. n=getint(),L=getint(),R=getint();
  103. for(int i=2,u,v;i<=n;i++){
  104. u=getint(),v=getint();
  105. to[++tt]=v;next[tt]=head[u];head[u]=tt;
  106. to[++tt]=u;next[tt]=head[v];head[v]=tt;
  107. c[tt-1]=c[tt]=getint();
  108. }
  109. getroot(1,0);
  110. for(int i=1;i<=n;i++) c1[i]=c2[i]=-1e9;
  111. double l=0,r=1000000,mid;
  112. while(r-l>=1e-4){
  113. mid=(l+r)*0.5;
  114. if(check(mid)) l=mid;
  115. else r=mid;
  116. }
  117. printf("%.3lf",l);
  118. return 0;
  119. }

  Dinkelbach迭代法代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<cmath>
  6. #include<vector>
  7. #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
  8. #define maxn 100010
  9. #define INF 2147483647
  10.  
  11. using namespace std;
  12. typedef long long llg;
  13.  
  14. int n,L,R,siz[maxn],dx[maxn],lc,dep[maxn];
  15. int fr[maxn<<1],a[maxn],la,d[maxn],ld,s[maxn];
  16. int head[maxn],next[maxn<<1],to[maxn<<1],tt;
  17. double c[maxn<<1],lt,dis[maxn];
  18. double c1[maxn],c2[maxn],ans;
  19. bool vis[maxn];
  20.  
  21. int getint(){
  22. int w=0;bool q=0;
  23. char c=getchar();
  24. while((c>'9'||c<'0')&&c!='-') c=getchar();
  25. if(c=='-') c=getchar(),q=1;
  26. while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
  27. return q?-w:w;
  28. }
  29.  
  30. bool cmp(int x,int y){return dep[to[x]]<dep[to[y]];}
  31. void link(int x,int y,int z){
  32. to[++tt]=y;next[tt]=head[x];
  33. head[x]=tt; c[tt]=z;
  34. }
  35.  
  36. void dfs(int u,int x){
  37. siz[u]=1; dx[u]=0; dep[u]=x;
  38. d[++ld]=u; vis[u]=1;
  39. for(int i=head[u],v;v=to[i],i;i=next[i])
  40. if(!vis[v]){
  41. dfs(v,x+1); siz[u]+=siz[v];
  42. dx[u]=max(dx[u],siz[v]);
  43. dep[u]=max(dep[u],dep[v]);
  44. }
  45. vis[u]=0;
  46. }
  47.  
  48. void getroot(int u,int fa){
  49. ld=0; dfs(u,0); int k=0,_k=INF;
  50. for(int l=1,i;i=d[l],l<=ld;l++){
  51. dx[i]=max(dx[i],siz[u]-siz[i]);
  52. if(dx[i]<_k) k=i,_k=dx[i];
  53. }
  54. vis[k]=1; fr[fa]=k;
  55. for(int i=head[k];i;i=next[i])
  56. if(!vis[to[i]]) getroot(to[i],i);
  57. ld=0; dfs(k,0); vis[k]=0; la=0;
  58. for(int i=head[k];i;i=next[i]) a[++la]=i;
  59. sort(a+1,a+la+1,cmp); next[a[la]]=0; head[k]=a[1];
  60. for(int i=1;i<la;i++) next[a[i]]=a[i+1];
  61. }
  62.  
  63. void getdis(int u,int de){
  64. vis[u]=1; lc=max(lc,de); c2[de]=max(c2[de],dis[u]);
  65. for(int i=head[u],v;v=to[i],i;i=next[i])
  66. if(!vis[v]) dis[v]=dis[u]+c[i],getdis(v,de+1);
  67. vis[u]=0;
  68. }
  69.  
  70. void work(int u,int fa){
  71. int k=fr[fa]; vis[k]=1; int cl=0; double x;
  72. for(int i=head[k],v,l,r,no;v=to[i],i;i=next[i]){
  73. if(vis[v]) continue; lc=0;
  74. dis[v]=c[i]; getdis(v,1); l=r=0; no=0;
  75. for(int j=lc;j;j--){
  76. while(no<=R-j && no<=cl){
  77. while(l<r && c1[s[r-1]]<=c1[no]) r--;
  78. s[r++]=no++;
  79. }
  80. while(l<r && s[l]<L-j) l++;
  81. if(l<r){
  82. x=(c2[j]+c1[s[l]])/(j+s[l]);
  83. if(x>ans) ans=x;
  84. }
  85. }
  86. cl=max(cl,lc);
  87. for(int j=1;j<=lc;j++) c1[j]=max(c1[j],c2[j]),c2[j]=-1e9;
  88. }
  89. for(int i=1;i<=cl;i++) c1[i]=-1e9;
  90. for(int i=head[k];i;i=next[i])
  91. if(!vis[to[i]]) work(to[i],i);
  92. vis[k]=0;
  93. }
  94.  
  95. void check(double x){
  96. for(int i=1;i<=tt;i++) c[i]+=lt-x; lt=x;
  97. ans=-1e9; work(1,0);
  98. }
  99.  
  100. int main(){
  101. File("a");
  102. n=getint(),L=getint(),R=getint();
  103. for(int i=2,u,v;i<=n;i++){
  104. u=getint(),v=getint();
  105. to[++tt]=v;next[tt]=head[u];head[u]=tt;
  106. to[++tt]=u;next[tt]=head[v];head[v]=tt;
  107. c[tt-1]=c[tt]=getint();
  108. }
  109. getroot(1,0);
  110. for(int i=1;i<=n;i++) c1[i]=c2[i]=-1e9;
  111. double now=0; check(0);
  112. while(ans>1e-4) now+=ans,check(now);
  113. printf("%.3lf",now);
  114. return 0;
  115. }

  实测BZOJ上前一份代码24s+,后一份代码只要5s+

BZOJ 1758 【WC2010】 重建计划的更多相关文章

  1. bzoj 1758 [Wc2010]重建计划 分数规划+树分治单调队列check

    [Wc2010]重建计划 Time Limit: 40 Sec  Memory Limit: 162 MBSubmit: 4345  Solved: 1054[Submit][Status][Disc ...

  2. bzoj 1758: [Wc2010]重建计划

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

  3. BZOJ.1758.[WC2010]重建计划(分数规划 点分治 单调队列/长链剖分 线段树)

    题目链接 BZOJ 洛谷 点分治 单调队列: 二分答案,然后判断是否存在一条长度在\([L,R]\)的路径满足权值和非负.可以点分治. 对于(距当前根节点)深度为\(d\)的一条路径,可以用其它子树深 ...

  4. BZOJ 1758: [Wc2010]重建计划 [暂时放弃]

    今天晚上思维比较乱,以后再写写吧#include <iostream> #include <cstdio> #include <cstring> #include ...

  5. BZOJ 1758: [Wc2010]重建计划 01分数规划+点分治+单调队列

    code: #include <bits/stdc++.h> using namespace std; #define setIO(s) freopen(s".in", ...

  6. BZOJ1758: [Wc2010]重建计划

    题解: 这题我居然做了一星期?... 平均值的极值其实也可以算是一种分数规划,只不过分母上b[i]=1 然后我们就可以二分这个值.类似与 HNOI最小圈 如果没有 链的长度的限制的话,我们直接两遍df ...

  7. 洛谷 P4292 [WC2010]重建计划 解题报告

    P4292 [WC2010]重建计划 题目描述 \(X\)国遭受了地震的重创, 导致全国的交通近乎瘫痪,重建家园的计划迫在眉睫.\(X\)国由\(N\)个城市组成, 重建小组提出,仅需建立\(N-1\ ...

  8. [WC2010]重建计划 长链剖分

    [WC2010]重建计划 LG传送门 又一道长链剖分好题. 这题写点分治的人应该比较多吧,但是我太菜了,只会长链剖分. 如果你还不会长链剖分的基本操作,可以看看我的长链剖分总结. 首先一看求平均值最大 ...

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

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

  10. 【bzoj1758】[Wc2010]重建计划

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

随机推荐

  1. [LeetCode] 549. Binary Tree Longest Consecutive Sequence II_ Medium tag: DFS recursive

    Given a binary tree, you need to find the length of Longest Consecutive Path in Binary Tree. Especia ...

  2. leetcode & lintcode 题解

    刷题备忘录,for bug-free 招行面试题--求无序数组最长连续序列的长度,这里连续指的是值连续--间隔为1,并不是数值的位置连续 问题: 给出一个未排序的整数数组,找出最长的连续元素序列的长度 ...

  3. MatLab 2014a编译jar包时mcc无法使用的问题

    http://blog.csdn.net/heroafei/article/details/43273373 MatLab 2014a编译jar包时mcc无法使用的问题 2015-01-29 16:5 ...

  4. JaveScript-简介

    1.JaveScript:脚本语言.(弱类型语言)可以写在head,也可以写在head里,同样可以写在html外面<script src=""></script& ...

  5. sql server 获取分隔字符串后的长度

    --方法1 --sql 分隔字符串,返回个数 CREATE function f_splitLen_1 (   @str varchar(1024),  --要分割的字符串   @split varc ...

  6. GCC编译器ABI

    ABI与EABI 1)ABI(Application Binary Interface for the ARM Architecture),描述了应用程序与cpu内核的低级接口. ABI允许编译好的目 ...

  7. How To View the HTML Source in Google Chrome

    Whether you are new to the web industry or a seasoned veteran, viewing the HTML source of different ...

  8. jq 自定义标注小组件 $.widget

    html 部分 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...

  9. org.apache.catalina.core.StandardWrapperValve invoke的解决办法

    org.apache.catalina.core.StandardWrapperValve invoke的解决办法 比较容易错的地方是页面带参数进行跳转,由于跳转之后的页面本身也要执行一部分sql语句 ...

  10. ES6学习笔记之map、set与数组、对象的对比

    ES6 ES5中的数据结构,主要是用Array和Object.在ES6中主要新增了Set和Map数据结构.到目前为止,常用的数据结构有四种Array.Object.Set.Map.下面话不多说了,来一 ...