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

Source

这个WC题与一道WG的题贼像!!!

然后这题的套路据说又与wfj_2048大佬的middle贼像!!!

这种求平均值和中位数的套路就是二分,具体对于这个题来说二分一个平均值,把所有的边的边权减去mid

剩下的就是判断是否有一条长度在[L,R]间的路权值大于0;也就是说求长度在[L,R]间的权值最大的边

我个傻逼想到这里就GG了,然后就只能堕落了,于是去翻了翻LightGod的博客,Orz,太厉害了

对于一个点,一条路径只有经过这个点,或不经过这个点两种情况,不经过这个点的情况就往下递归,我们考虑经过这个点的情况

对于一条简单路径,他必定是在这个点的子树中选取两条不在同一子树中的路径进行相加

于是这个东西可以用单调队列来维护一个滑动窗口,(ANS[i]记录长度为i的权值最大的路径)

具体做法是这样:

我们考虑这个点的每个儿子管理的连通块(在每个儿子getdis的时候把该儿子管辖下的连通块中每个长度的权值最大值记录下来)

那么我们枚举处理该儿子的记录下来的边(每个长度的权值最大的边),假设长度为i,那么对于其他子树中长度的取值范围就是[L-i,R-i];

然后我们用普通单调队列的处理,处理完后这个儿子后再拿这个儿子的所有边去更新ANS.

对于每个点可以O(size)维护该点的最优值;

然后这个题就打完了...然后调了好久,是一个函数名打错了

附上代码:

// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<queue>
#include<set>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#define lson num<<1
#define rson num<<1|1
#define deepmaxlen dml
using namespace std;
typedef long long ll;
const int N=500050;
const int Inf=2147483647;
const double eps=1e-5;
int gi()
{
int x=0,flag=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*flag;
}
int head[N],to[N],nxt[N];
int size[N],f[N],deep[N],rt[N],vis[N],q[N];
double dml[N],ANS[N],ans=-Inf,c[N],dis[N];
int SIZE,root,cnt,tot,tot2,L,R,M_DEP,n;
struct data{
int id,dep;
}son[N];
bool cmp(data a,data b){
return a.dep<b.dep;
}
void lnk(int x,int y,int v){
to[++cnt]=y,c[cnt]=(double)v,nxt[cnt]=head[x],head[x]=cnt;
to[++cnt]=x,c[cnt]=(double)v,nxt[cnt]=head[y],head[y]=cnt;
}
void getroot(int x,int fa){
size[x]=1;f[x]=0;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(!vis[y]&&y!=fa){
getroot(y,x);
size[x]+=size[y];
f[x]=max(f[x],size[y]);
}
}
f[x]=max(f[x],SIZE-size[x]);
if(f[x]<f[root]) root=x;
}
void get_maxdis(int x,int fa){
dml[deep[x]]=max(dml[deep[x]],dis[x]);
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y!=fa&&!vis[y]){
dis[y]=dis[x]+c[i];
get_maxdis(y,x);
}
}
}
void get_deep(int x,int fa){
;M_DEP=max(M_DEP,deep[x]);
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y!=fa&&!vis[y]){
deep[y]=deep[x]+1;
get_deep(y,x);
}
}
}
void work(int x){
rt[++tot]=x;vis[x]=1;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(!vis[y]){
root=0;SIZE=size[y];getroot(y,0);
work(root);
}
}
}
void work2(int x){
tot2++;x=rt[tot2];int cnt2=0;vis[x]=1;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(!vis[y]){
dis[y]=c[i];
M_DEP=deep[y]=1;get_deep(y,x);
son[++cnt2]=(data){y,M_DEP};
}
}
int last=0;
sort(son+1,son+1+cnt2,cmp);
for(int i=1;i<=cnt2;i++){
get_maxdis(son[i].id,x);
int st=1,ed=0,l=last,r=last;
for(int j=1;j<=son[i].dep;j++){
while(l>=0&&l>=L-j){
while(st<=ed&&ANS[q[ed]]<ANS[l]) ed--;
q[++ed]=l--;
}
for(;r>=0&&r+j>R;r--) while(st<=ed&&q[st]>=r) st++;
if(st<=ed) ans=max(ans,dml[j]+ANS[q[st]]);
}
for(int j=1;j<=son[i].dep;j++) ANS[j]=max(ANS[j],dml[j]),dml[j]=(double)-Inf;
last=max(last,son[i].dep);
}
for(int i=1;i<=last;i++) ANS[i]=(double)-Inf;
if(ans>=0) return;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(!vis[y]){
work2(y);
}
}
}
bool check(double mid){
for(int i=1;i<=cnt;i++) c[i]-=mid;
for(int i=1;i<=n;i++) vis[i]=0,dis[i]=0,deep[i]=0;ans=-Inf;
tot2=0;work2(rt[1]);
for(int i=1;i<=cnt;i++) c[i]+=mid;
return ans>=0;
}
int main(){
n=gi();L=gi();R=gi();
int x,y,z;
for(int i=1;i<n;i++){
x=gi(),y=gi(),z=gi();lnk(x,y,z);
}
for(int i=1;i<=n;i++) dml[i]=ANS[i]=-Inf;
root=0;f[0]=Inf;SIZE=n;getroot(1,0);work(root);
double l=0,r=1000000;
while(r-l>eps){
double mid=(l+r+eps)/2;
if(check(mid))l=mid;
else r=mid-eps;
}
printf("%.3lf",l);
}

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]重建计划(分数规划 点分治 单调队列/长链剖分 线段树)

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

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

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

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

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

  5. BZOJ1758: [Wc2010]重建计划

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

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

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

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

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

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

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

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

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

随机推荐

  1. liunx中图形化桌面环境中的脚本编程之——创建文本菜单

    整体是通过建立菜单布局,然后根据菜单上的布局建立函数(就是为这些布局实现功能),最后将函数和布局实现逻辑上的相连: 如何建立菜单布局? 整体上是通过打印字符创建出,因此需要使用echo命令,但是有一些 ...

  2. 中英文代码对比系列之Java一例

    原文: https://zhuanlan.zhihu.com/p/30905033. 作者为本人. 这个系列将对同一段代码进行中文命名和英文命名两个版本的比较. 目的包括, 演示中文命名, 发现命名时 ...

  3. 当final作用于变量、参数、方法和类时该如何处理

    final变量: 对于基本类型使用final:它就是一个常量,数值恒定不变 对于对象引用使用final:使得引用恒定不变,一旦引用被初始化指向一个对象,就无法再把 它改为指向另一个对象.然而,对象自身 ...

  4. IntelliJ IDEA(三) :常用快捷键

    说IDEA对新手来说难,可能其中一个原因就是快捷键组合多而且复杂但是它也很全,基本所有功能都可以通过快捷键来完成,可以这么说,如果你掌握了所有IDEA的快捷键使用,那么你完全可以丢掉鼠标,而且不影响开 ...

  5. PHP 获取ip地址

    public function getIP() { if (getenv("HTTP_CLIENT_IP")) $ip = getenv("HTTP_CLIENT_IP& ...

  6. WPF依赖对象(DependencyObject) 实现源码,理解WPF原理必读

    /// DependencyObject encompasses all property engine services. It's primary function /// is providin ...

  7. tensorflow MNIST新手教程

    官方教程代码如下: import gzip import os import tempfile import numpy from six.moves import urllib from six.m ...

  8. 遍历输出tuple元素的简洁方式(C++11)

    //遍历输出tuple元素的简洁方式(C++11) //Win32Con17_VS2017_01.cpp #include <iostream> #include <tuple> ...

  9. UILabel 的使用

    直接上代码: /* UILabel 使用 */ UILabel *aLable = [[UILabel alloc] initWithFrame:self.window.bounds]; aLable ...

  10. linux命令的排列、替换与别名

    命令的排列; 1.使用";" 命令语法: 命令1;命令2 当运行该命令时,无论命令1是否出错.接下来就运行命令2 2.使用"&&" 命令语法:命 ...