【bzoj1758】 Wc2010—重建计划
http://www.lydsy.com/JudgeOnline/problem.php?id=1758 (题目链接)
题意
给出一棵树,每条边有边权,问选出一条长度为$[L,U]$的路径,使得路径上的边权平均数最大是多少。
Solution
哈哈,爸爸终于过啦。
首先二分答案,然后路径统计显然点分治,统计答案的时候单调队列维护一下滑动窗口里面的最值。因为要点分治若干次,我们不妨将重心预处理出来,减少常数。
一定要小心,在点分治处理子树的时候,一定要按照深度从小到大的顺序处理,不然直接被新加的那组扫把型的数据卡掉T_T。
细节
清空cnt。
代码
// bzoj1758
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define LD long double
#define eps 1e-4
#define inf (1ll<<60)
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std; const int maxn=100010;
int n,m,U,L,cnt,head[maxn];
struct edge {int to,next,w;}e[maxn<<1];
struct data {
int num,D;
friend bool operator < (data a,data b) {return a.D>b.D;}
}; namespace NodeDivide {
int Dargen,rt,D,maxD,sum,size[maxn],vis[maxn],Sum[maxn],f[maxn],q[maxn],h[maxn];
edge t[maxn];
double ans,deep[maxn],dis[maxn],Dis[maxn];
void link(int u,int v) {t[++cnt]=(edge){v,h[u]};h[u]=cnt;}
void dfs(int x,int fa) {
size[x]=f[x]=1;
for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && !vis[e[i].to]) {
dfs(e[i].to,x);
f[x]=max(f[x],size[e[i].to]);
size[x]+=size[e[i].to];
}
f[x]=max(f[x],sum-size[x]);
if (f[x]<f[rt]) rt=x;
}
void caldeep(int x,int fa,int d) {
D=max(D,d);
for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && !vis[e[i].to]) {
deep[e[i].to]=deep[x]+e[i].w;
caldeep(e[i].to,x,d+1);
}
}
void caldis(int x,int fa,int d) {
dis[d]=max(dis[d],deep[x]);
for (int i=head[x];i;i=e[i].next)
if (e[i].to!=fa && !vis[e[i].to]) caldis(e[i].to,x,d+1);
}
void solve(int x,double res) {
vis[x]=1;maxD=0;
priority_queue<data> T;
for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to]) {
D=0;deep[e[i].to]=e[i].w;
caldeep(e[i].to,x,1);
T.push((data){e[i].to,D});
}
while (!T.empty()) {
data tmp=T.top();T.pop();
caldis(tmp.num,x,1);
int l=1,r=0,pl=maxD,pr=maxD;
for (int i=1;i<=tmp.D;i++) {
for (;pl>-1 && pl>=L-i;pl--) {
while (l<=r && Dis[q[r]]-q[r]*res<Dis[pl]-pl*res) r--;
q[++r]=pl;
}
for (;pr>-1 && pr>U-i;pr--) while (l<=r && q[l]>=pr) l++;
if (pl<pr) ans=max(ans,dis[i]-i*res+Dis[q[l]]-q[l]*res);
}
maxD=max(maxD,tmp.D);
for (int i=1;i<=tmp.D;i++) Dis[i]=max(Dis[i],dis[i]),dis[i]=0;
}
for (int i=1;i<=maxD;i++) Dis[i]=0;
for (int i=h[x];i;i=t[i].next) if (Sum[t[i].to]>=L) solve(t[i].to,res);
vis[x]=0;
}
void caldargen(int x,int fa) {
vis[x]=1;
if (fa) link(fa,x);else Dargen=x;
for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to]) {
sum=size[e[i].to],rt=0;
dfs(e[i].to,x);
Sum[rt]=sum;
caldargen(rt,x);
}
vis[x]=0;
}
void Init() {
cnt=0;
sum=n;f[rt=0]=1<<30;
dfs(1,0);Sum[rt]=sum;
caldargen(rt,0);
}
double main(double res) {
ans=-inf;
solve(Dargen,res);
return ans;
}
}
using namespace NodeDivide; void link(int u,int v,int w) {
e[++cnt]=(edge){v,head[u],w};head[u]=cnt;
e[++cnt]=(edge){u,head[v],w};head[v]=cnt;
}
int main() {
scanf("%d%d%d",&n,&L,&U);
for (int u,v,w,i=1;i<n;i++) {
scanf("%d%d%d",&u,&v,&w);
link(u,v,w);
}
Init();
double l=0,r=1000000,ans;
while (l<=r) {
double mid=(l+r)/2;
if (main(mid)>=0) l=mid+eps,ans=mid;
else r=mid-eps;
}
printf("%.3lf",ans);
return 0;
}
【bzoj1758】 Wc2010—重建计划的更多相关文章
- BZOJ1758: [Wc2010]重建计划
题解: 这题我居然做了一星期?... 平均值的极值其实也可以算是一种分数规划,只不过分母上b[i]=1 然后我们就可以二分这个值.类似与 HNOI最小圈 如果没有 链的长度的限制的话,我们直接两遍df ...
- bzoj1758 [Wc2010]重建计划 & bzoj2599 [IOI2011]Race
两题都是树分治. 1758这题可以二分答案avgvalue,因为avgvalue=Σv(e)/s,因此二分后只需要判断Σv(e)-s*avgvalue是否大于等于0,若大于等于0则调整二分下界,否则调 ...
- BZOJ1758[Wc2010]重建计划——分数规划+长链剖分+线段树+二分答案+树形DP
题目描述 输入 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai, ...
- [BZOJ1758][WC2010]重建计划(点分治+单调队列)
点分治,对于每个分治中心,考虑求出经过它的符合长度条件的链的最大权值和. 从分治中心dfs下去取出所有链,为了防止两条链属于同一个子树,我们一个子树一个子树地处理. 用s1[i]记录目前分治中心伸下去 ...
- BZOJ1758: [Wc2010]重建计划(01分数规划+点分治+单调队列)
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1758 01分数规划,所以我们对每个重心进行二分.于是问题转化为Σw[e]-mid>=0, ...
- BZOJ1758 WC2010 重建计划 二分答案、点分治、单调队列
传送门 看到平均数最大,自然地想到二分答案.那么我们的$check$函数就是要求:是否存在一条长度在$[L,U]$的路径,满足其权值和$\geq 0$. 看到长度在$[L,U]$,自然地想到点分治求解 ...
- 2019.01.21 bzoj1758: [Wc2010]重建计划(01分数规划+长链剖分+线段树)
传送门 长链剖分好题. 题意简述:给一棵树,问边数在[L,R][L,R][L,R]之间的路径权值和与边数之比的最大值. 思路: 用脚指头想都知道要01分数规划. 考虑怎么checkcheckcheck ...
- 洛谷 P4292 [WC2010]重建计划 解题报告
P4292 [WC2010]重建计划 题目描述 \(X\)国遭受了地震的重创, 导致全国的交通近乎瘫痪,重建家园的计划迫在眉睫.\(X\)国由\(N\)个城市组成, 重建小组提出,仅需建立\(N-1\ ...
- [WC2010]重建计划 长链剖分
[WC2010]重建计划 LG传送门 又一道长链剖分好题. 这题写点分治的人应该比较多吧,但是我太菜了,只会长链剖分. 如果你还不会长链剖分的基本操作,可以看看我的长链剖分总结. 首先一看求平均值最大 ...
- bzoj 1758 [Wc2010]重建计划 分数规划+树分治单调队列check
[Wc2010]重建计划 Time Limit: 40 Sec Memory Limit: 162 MBSubmit: 4345 Solved: 1054[Submit][Status][Disc ...
随机推荐
- js实现60秒倒计时效果(使用了jQuery)
今天碰到要实现一个类似那种短信验证码60秒倒计时的需求,好久不写js,有点手生.把代码记录下,方便后续查阅. 这里我用了jQuey,毕竟写起来简洁点.下面直接看效果和代码. 一.效果 ...
- EZ 2018 01 14 2018noip第四次膜你赛
这次惨烈的炸了个精光(只有20),然后对我的OI想法造成了巨大的转折. (以上有点作,其实我只是再也不用vector存图了而已(用邻接表)) 难度很不均匀,而且题型很狗(还有结论题???) T1 坑人 ...
- mfc 动态为控件添加事件1
知识点: 认识窗口过程 GetWindowLong SetWindowLong 为动态控件绑定事件 一.获取窗口过程 二.设置新窗口过程 .书写一个新窗口过程函数 窗口过程格式 LRESULT CAL ...
- bootstrap-validator基本使用(自定义验证身份证号和手机号)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...
- laraver框架学习------工厂模型填充测试数据
在laravel中填充数据有几种方式.一种是Seeder,另一种是工厂模式进行的填充. 工厂模式可以实现大批量的填充数据,数据的量可以自定义.这也为后续的软件测试提供方便. 在laravel框架有da ...
- Jmeter(四)_16个逻辑控制器详解
循环控制器: 指定其子节点运行的次数,可以使用具体的数值,也可以设置为变量 1:勾选永远:表示一直循环下去 2:如果同时设置了线程组的循环次数和循环控制器的循环次数,那循环控制器的子节点运行的次数为两 ...
- [翻译]:Artificial Intelligence for games 5.3 STATE MACHINES:状态机
目录 Chapter 5 Decision Making 5.3 STATE MACHINES:状态机 Chapter 5 Decision Making 5.3 STATE MACHINES:状态机 ...
- 利用顺序栈解决括号匹配问题(c++)-- 数据结构
题目: 7-1 括号匹配 (30 分) 给定一串字符,不超过100个字符,可能包括括号.数字.字母.标点符号.空格,编程检查这一串字符中的( ) ,[ ],{ }是否匹配. 输入格式: 输入在一行 ...
- LeetCode-765.情侣牵手
N 对情侣坐在连续排列的 2N 个座位上,想要牵到对方的手. 计算最少交换座位的次数,以便每对情侣可以并肩坐在一起. 一次交换可选择任意两人,让他们站起来交换座位. 人和座位用 0 到 2N-1 的整 ...
- 软件项目第一次sprint评分表