【bzoj1758】[Wc2010]重建计划

Description

Input

第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai,Bi,Vi分别表示道路(Ai,Bi),其价值为Vi 其中城市由1..N进行标号

Output

输出最大平均估值,保留三位小数

Sample Input

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

Sample Output

2.500

HINT

N<=100000,1<=L<=U<=N-1,Vi<=1000000 新加数据一组 By leoly,但未重测..2016.9.27

题解:

  好一个扫把树……长见识长见识。

  显然二分答案+树的点分治。每次遍历一棵子树来得到$dis$数组,表示同一路径数的最大权值,然后再存一个之前遍历子树的桶,含义与$dis$一样,但是要注意从小到大处理每棵子树。扫把树……卡死人。

  顺便一提,bzoj不会爆栈。

  (空行比较多,所以显得很长……)

  1 #define Troy 09/30/2017
  2
  3 #define inf 0x7fffffff
  4
  5 #include <bits/stdc++.h>
  6
  7 using namespace std;
  8
  9 typedef long long ll;
 10
 11 const int N=500100;
 12 const double eps=1e-4;
 13
 14 inline int read(){
 15     int s=0,k=1;char ch=getchar();
 16     while(ch<‘0‘|ch>‘9‘)  ch==‘-‘?k=-1:0,ch=getchar();
 17     while(ch>47&ch<=‘9‘)  s=s*10+(ch^48),ch=getchar();
 18     return s*k;
 19 }
 20
 21 struct edges{
 22     int v;ll w;edges *last;
 23 }edge[N<<1],*head[N];int cnt;
 24
 25 inline void push(int u,int v,ll w){
 26     edge[++cnt]=(edges){v,w,head[u]};head[u]=edge+cnt;
 27 }
 28
 29 int n,up,low,tot,top,root,size[N],heavy[N],T[N],Tdis[N],part,from;
 30 ll t[N],dis[N];
 31 bool vis[N];
 32 double ans,maxr;
 33
 34 inline void dfs(int x,int fa,int deep){
 35     size[x]=1;
 36     heavy[x]=0;
 37     for(edges *i=head[x];i;i=i->last)if(i->v!=fa&&(!vis[i->v])){
 38         dfs(i->v,x,deep+1);
 39         size[x]+=size[i->v];
 40         heavy[x]=max(size[i->v],heavy[x]);
 41     }
 42     heavy[x]=max(heavy[x],tot-size[x]);
 43     if(heavy[x]<top)
 44         top=heavy[x],root=x;
 45 }
 46
 47 inline void calc(int x,int fa,ll d,int lens){
 48     if(lens>up)  return ;
 49     if(Tdis[lens]!=part){
 50         Tdis[lens]=part;
 51         dis[lens]=d;
 52     }else
 53         dis[lens]=max(dis[lens],d);
 54     for(edges *i=head[x];i;i=i->last)    if(i->v!=fa&&(!vis[i->v])){
 55         calc(i->v,x,d+i->w,lens+1);
 56     }
 57 }
 58
 59 inline void get_new(int x,int fa,ll d,int lens){
 60     if(lens>up)  return;
 61     if(T[lens]!=T[0])
 62         T[lens]=T[0],t[lens]=d;
 63     else
 64         t[lens]=max(t[lens],d);
 65     from=max(from,lens);
 66     for(edges *i=head[x];i;i=i->last)    if(i->v!=fa&&(!vis[i->v])){
 67         get_new(i->v,x,d+i->w,lens+1);
 68     }
 69 }
 70
 71 int q[N];
 72 double nq[N];
 73
 74 inline bool Judge(double x){
 75     int l=0,r=0;
 76     int pos=min(up-1,from);
 77     bool flag=1;
 78     while(pos>=low){
 79         if(T[pos]!=T[0]){
 80             pos--;continue;
 81         }
 82         while(r>l&&nq[r-1]<t[pos]-x*pos)
 83             r--;
 84         nq[r]=t[pos]-x*pos;
 85         q[r++]=pos;
 86         pos--;
 87     }
 88     for(int i=low-pos;i<=up;i++){
 89         if(Tdis[i]!=part)   break;
 90         if(pos>=0&&i+pos>=low&&T[pos]==T[0]){
 91             while(r>l&&nq[r-1]<t[pos]-x*pos)
 92                 r--;
 93             nq[r]=t[pos]-x*pos;
 94             q[r++]=pos;
 95         }
 96         while(l<r&&q[l]+i>up)
 97             l++;
 98         pos--;
 99         if(l<r&&nq[l]+dis[i]-i*x>=0)
100             return true;
101     }
102     return false;
103 }
104
105 struct node{
106     int v,w;
107     friend bool operator <(node x,node y){
108         return size[x.v]<size[y.v];
109     }
110 }sons[N];
111
112
113 inline void solve(int u){
114     tot=size[u];
115     top=inf;
116     dfs(u,u,0);
117     vis[root]=true;
118     T[0]++;
119     from=1;
120     int cc=0;
121     for(edges *i=head[root];i;i=i->last)if(!vis[i->v]){
122         cc++;
123         sons[cc].v=i->v;
124         sons[cc].w=i->w;
125     }
126     sort(sons+1,sons+1+cc);
127     for(int i=1;i<=cc;i++){
128         if(i>1){
129                 part++;
130                 calc(sons[i].v,0,sons[i].w,1);
131                 double l=ans,r=maxr,mid;
132                 while(l<r-eps){
133                     mid=(l+r)/2;
134                     if(Judge(mid))  l=mid;
135                     else    r=mid;
136                 }
137                 ans=l;
138             }
139             if(i<cc)
140                 get_new(sons[i].v,0,sons[i].w,1);
141     }
142     for(edges *i=head[root];i;i=i->last) if(!vis[i->v])
143         solve(i->v);
144 }
145
146 int main(){
147     n=read();
148     low=read(),up=read();
149     for(int i=1,u,v,w;i<n;i++){
150         u=read(),v=read(),w=read();
151         push(u,v,w),push(v,u,w);
152         maxr=max(maxr,w+0.0);
153     }
154     size[1]=n;
155     solve(1);
156     printf("%.3lf\n",ans);
157 }

 

时间: 2025-01-11 13:18:09

【bzoj1758】[Wc2010]重建计划的相关文章

bzoj1758 [Wc2010]重建计划

Description Input 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai,Bi,Vi分别表示道路(Ai,Bi),其价值为Vi 其中城市由1..N进行标号 Output 输出最大平均估值,保留三位小数 Sample Input 4 2 3 1 2 1 1 3 2 1 4 3 Sample Output 2.500 HINT N<=100000,1<=L

bzoj1758 [Wc2010]重建计划 &amp; bzoj2599 [IOI2011]Race

两题都是树分治. 1758这题可以二分答案avgvalue,因为avgvalue=Σv(e)/s,因此二分后只需要判断Σv(e)-s*avgvalue是否大于等于0,若大于等于0则调整二分下界,否则调整二分上界.假设一棵树树根为x,要求就是经过树根x的最大答案,不经过树根x的可以递归求解.假设B[i]为当前做到的一颗x的子树中的点到x的距离为i的最大权值,A[i]为之前已经做过的所有子数中的点到x的距离为i的最大权值(这里的权值是Σv(e)-i*avgvalue),那么对于当前子树的一个距离i,

BZOJ1758: [Wc2010]重建计划(01分数规划+点分治+单调队列)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1758 01分数规划,所以我们对每个重心进行二分.于是问题转化为Σw[e]-mid>=0, 对于一棵子树维护点的dep,dis,并用队列q存下来.令mx[i]表示当前dep为i的最大权值,维护一个单调队列dq,维护当前符合条件的mx,当我们从q的队尾向前扫时,它的dep是递减的,利用这个性质维护单调队列,最后更新一遍mx.具体看代码吧TAT 代码: #include<cstring>#

【BZOJ 1758】 [Wc2010]重建计划

1758: [Wc2010]重建计划 Time Limit: 40 Sec  Memory Limit: 162 MB Submit: 989  Solved: 345 [Submit][Status] Description Input 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai,Bi,Vi分别表示道路(Ai,Bi),其价值为Vi 其中城市由1..N进行标

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

[Wc2010]重建计划 Time Limit: 40 Sec  Memory Limit: 162 MBSubmit: 4345  Solved: 1054[Submit][Status][Discuss] Description Input 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai,Bi,Vi分别表示道路(Ai,Bi),其价值为Vi 其中城市由1..N

[BZOJ]1758: [Wc2010]重建计划

题目大意:给定一棵n个点的带边权的树和l,u,求长度在[l,u]之间平均权值最大的链的权值.(n<=100,000) 思路:二分答案,把树上每条边减去二分出的答案,点分治check是否有长度在[l,u]之间权值和大等0的链,每次把每棵子树按深度排序,记下各个深度到根距离最大的节点,再用单调队列统计即可,总复杂度O(nlogn^2).此题卡常差评,重心只要算一次,不用每次二分都算,稍微卡卡就过了. #include<cstdio> #include<cstring> #incl

BZOJ 1758 Wc2010 重建计划 树的点分治+二分+单调队列

题目大意:给定一棵树,询问长度在[l,u]范围内的路径中边权的平均值的最大值 01分数规划,首先想到二分答案 既然是统计路径肯定是点分治 每次统计时我们要找有没有大于0的路径存在 那么对于一棵子树的每一个深度i记录一个路径权值和的最大值 然后在这棵子树之前的所有子树的深度可选范围就是[l-i,u-i] 这个窗口是不停滑动的 因此用单调队列维护最大值即可 ↑上面这些网上的题解都说的还是蛮详细的 据说二分套在树分治里面会快一些 但是 尼玛 我被卡常了!! 这里只提供一些剪枝 1.当前分治的总点数<=

UOJ#54 [WC2010]重建计划

题目描述 小 X 驾驶着他的飞船准备穿梭过一个 \(n\) 维空间,这个空间里每个点的坐标可以用 \(n\) 个实数表示,即 \((x_1,x_2,\dots,x_n)\). 为了穿过这个空间,小 X 需要在这个空间中选取 \(c\)(\(c\geq 2\))个点作为飞船停留的地方,而这些点需要满足以下三个条件: 每个点的每一维坐标均为正整数,且第 \(i\) 维坐标不超过 \(m_i\). 第 \(i+1\)(\(1\leq i<c\))个点的第 \(j\)(\(1\leq j\leq n\)

P4292 [WC2010]重建计划

传送门 首先这玩意儿很明显是分数规划,二分一个答案\(mid\),边权变为\(w_i-mid\),然后看看能不能找到一条路径长度在\([L,R]\)之间,且边权总和非负,这个可以转化为求一条满足条件的边权最大的路径 这个实际上可以用点分做,用单调队列可以优化到\(O(nlog^2n)\),然而我不知道为什么写挂掉了所以这里就不说了-- 我们设\(f_{i,j}\)表示以\(i\)为根的子树中,从\(i\)向下走\(j\)步的链最长是多少.转移可以用长链剖分优化到均摊\(O(1)\).查询答案的话