[WC 2010]重建计划

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

题解

本机实测是可以 $A$ 的,但爆炸 $oj$ 的老爷机实在不可恭维,并且还多加了一组更为毒瘤的数据...

加了所有的常数优化都过不了,气愤的不想写题解,直接丢链接。

->题解在这里<-

  1 //It is made by Awson on 2018.1.5
  2 #include <set>
  3 #include <map>
  4 #include <cmath>
  5 #include <ctime>
  6 #include <queue>
  7 #include <stack>
  8 #include <cstdio>
  9 #include <string>
 10 #include <vector>
 11 #include <cstdlib>
 12 #include <cstring>
 13 #include <iostream>
 14 #include <algorithm>
 15 #define LL long long
 16 #define RE register
 17 #define lowbit(x) ((x)&(-(x)))
 18 #define Max(a, b) ((a) > (b) ? (a) : (b))
 19 #define Min(a, b) ((a) < (b) ? (a) : (b))
 20 using namespace std;
 21 const int N = 100000;
 22 const int INF = ~0u>>1;
 23 const double eps = 4e-4;
 24 void read(int &x) {
 25     char ch; x = 0;
 26     ch = getchar(); while (ch < ‘0‘ || ch > ‘9‘) ch = getchar();
 27     while (ch >= ‘0‘ && ch <= ‘9‘) x = (x<<1)+(x<<3)+ch-48, ch = getchar();
 28 }
 29
 30 int n, L, U, a, b, c;
 31 struct tt {
 32     int to, next;
 33     double cost, c;
 34 }edge[(N<<1)+5];
 35 int path[N+5], top;
 36 int root[N+5];
 37 void add(int u, int v, double c) {
 38     edge[++top].to = v;
 39     edge[top].cost = edge[top].c = c;
 40     edge[top].next = path[u];
 41     path[u] = top;
 42 }
 43
 44 namespace PRE {
 45     int size[N+5], mx[N+5], minsize, rt, vis[N+5], tot;
 46     void get_root(int o, int pa, int fa) {
 47     mx[o] = Max(mx[o], size[pa]-size[o]);
 48     if (mx[o] < minsize) minsize = mx[o], rt = o;
 49     for (RE int i = path[o]; i; i = edge[i].next)
 50         if (edge[i].to != fa && !vis[edge[i].to]) get_root(edge[i].to, pa, o);
 51     }
 52     void get_size(int o, int fa) {
 53     size[o] = 1, mx[o] = 0;
 54     for (RE int i = path[o]; i; i = edge[i].next)
 55         if (edge[i].to != fa && !vis[edge[i].to]) {
 56         get_size(edge[i].to, o);
 57         size[o] += size[edge[i].to];
 58         if (size[edge[i].to] > mx[o]) mx[o] = size[edge[i].to];
 59         }
 60     }
 61     void work(int o) {
 62     minsize = INF;
 63     get_size(o, 0), get_root(o, o, 0);
 64     root[++tot] = rt, vis[rt] = 1;
 65     for (RE int i = path[rt]; i; i = edge[i].next)
 66         if (!vis[edge[i].to]) work(edge[i].to);
 67     }
 68     void main() {work(1); }
 69 }
 70
 71 double mx[N+5], dist[N+5];
 72 int q[N+5], vis[N+5], dep[N+5], dq[N+5], fa[N+5];
 73
 74 bool cal(int o) {
 75     int maxdep = 0;
 76     for (RE int I = path[o]; I; I = edge[I].next)
 77     if (!vis[edge[I].to]) {
 78         int head = 0, tail = 0; q[tail] = edge[I].to, dep[q[0]] = 1, dist[q[0]] = edge[I].cost, fa[q[0]] = o, ++tail;
 79         while (head < tail) {
 80         int now = q[head]; ++head;
 81         for (RE int i = path[now]; i; i = edge[i].next)
 82             if (fa[now] != edge[i].to && !vis[edge[i].to]) {
 83             q[tail] = edge[i].to, ++tail;
 84             dep[edge[i].to] = dep[now]+1;
 85             dist[edge[i].to] = dist[now]+edge[i].cost;
 86             fa[edge[i].to] = now;
 87             }
 88         }
 89         int head1 = 0, tail1 = 0, now = maxdep;
 90         for (RE int i = 0; i < tail; ++i) {
 91         int x = q[i];
 92         while (dep[x]+now >= L && now >= 0) {
 93             while (head1 < tail1 && mx[dq[tail1-1]] < mx[now]) --tail1;
 94             dq[tail1] = now; ++tail1, --now;
 95         }
 96         while (head1 < tail1 && dq[head1]+dep[x] > U) ++head1;
 97         if (head1 < tail1 && dist[x]+mx[dq[head1]] >= 0) return true;
 98         }
 99         maxdep = Max(maxdep, dep[q[tail-1]]);
100         for (RE int i = 0; i < tail; ++i) {
101         fa[q[i]] = 0; if (mx[dep[q[i]]] < dist[q[i]]) mx[dep[q[i]]] = dist[q[i]];
102         }
103     }
104     for (RE int i = 1; i <= maxdep; i++) mx[i] = -INF;
105     return false;
106 }
107 bool solve(int o, int &num) {
108     vis[o] = 1;
109     if (cal(o)) return true;
110     for (RE int i = path[o]; i ;i = edge[i].next)
111     if (!vis[edge[i].to]) {
112         ++num; if (solve(root[num], num)) return true;
113     }
114     return false;
115 }
116 void pre(double key) {
117     for (RE int i = 1; i <= n; ++i) {
118     edge[i<<1].cost = edge[i<<1].c-key, edge[(i<<1)-1].cost = edge[(i<<1)-1].c-key;
119     vis[i] = 0, mx[i] = -INF;
120     }
121 }
122 void work() {
123     read(n), read(L), read(U);
124     double L = 0, R = 0;
125     for (RE int i = 1; i < n; ++i) {
126     read(a), read(b), read(c);
127     add(a, b, c), add(b, a, c); if (R < c) R = c;
128     }
129     PRE::main();
130     while (R-L > eps) {
131     double mid = (L+R)/2.; pre(mid);
132     int tot = 1;
133     if (solve(root[1], tot)) L = mid;
134     else R = mid;
135     }
136     printf("%.3lf\n", (L+R)/2.);
137 }
138 int main() {
139     work();
140     return 0;
141 }

原文地址:https://www.cnblogs.com/NaVi-Awson/p/8206689.html

时间: 2024-10-17 10:22:34

[WC 2010]重建计划的相关文章

【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】【WC 2010】重建计划 分数规划+点分治+单调队列

一开始看到$\frac{\sum_{}}{\sum_{}}$就想到了01分数规划但最终还是看了题解 二分完后的点分治,只需要维护一个由之前处理过的子树得出的$tb数组$,然后根据遍历每个当前的子树上的结点的深度来确定$tb数组$中的滑块. 因为分数规划要找的是$max$,BFS遍历当前结点的深度越来越大,这样滑块也是单调向右滑动,所以滑块里的最大值就应当用单调队列解决 #include<cstdio> #include<algorithm> #define read(x) x=ge

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

sharepoint 2010 重建遇到的问题

需要重新安装Sharepoint 2010 ,遇到问题记录下来,sharepoint中安装了热补丁和英文语言包. 卸载: 1.运行配置向导将服务器从服务场中脱离: 2.在管理中心中卸载sharepoint 2010. 没有卸载补丁(不知道在哪里卸载)和语言包(懒病). 从新安装: 1.安装sharepoint 2010文件: 2.安装补丁(这里遇到问题) 3.安装语言包. 在安装补丁的时候提示“未在系统中找到期望的版本”,本来已经安装了热补丁,我以为重新安装一下就可以了,没想到会出现这个问题,很

【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

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

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

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>#