题目: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>
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<queue>
#include<set>
#include<cmath>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define maxn 209000
#define inf int(1e9)
#define mm 1000000007
#define esp 1e-6
using namespace std;
#define ll long long
struct data{int obj,pre; double c;
}e[maxn*2];
int head[maxn],s[maxn],q[maxn],dq[maxn],dep[maxn],fa[maxn],vis[maxn];
double ans,lim,dis[maxn],mx[maxn];
int n,m,tot,sum,mn,rt,L,U;
int read(){
    int x=0,f=1; char ch=getchar();
    while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    return x*f;
}
void insert(int x,int y,double z){
    e[++tot].obj=y; e[tot].c=z; e[tot].pre=head[x]; head[x]=tot;
}
void dfs(int u,int fa){
    s[u]=1; int mx=0;
    for (int j=head[u];j;j=e[j].pre){
        int v=e[j].obj;
        if (v!=fa&&!vis[v]) {
            dfs(v,u);
            s[u]+=s[v];
            mx=max(mx,s[v]);
        }
    }
    mx=max(mx,sum-mx);
    if (mx<mn) mn=mx,rt=u;
}
bool go(int u,double mid){
    int up=0;
    for (int j=head[u];j;j=e[j].pre){
        int v=e[j].obj;  
        if (vis[v]) continue;
        dep[v]=1; dis[v]=e[j].c-mid; fa[v]=u;
        int l=0,r=1; q[1]=v;
        while (l<r){
            int now=q[++l];
            for (int k=head[now];k;k=e[k].pre){
                int v=e[k].obj;
                if (v!=fa[now]&&!vis[v]){
                    fa[v]=now; dep[v]=dep[now]+1; dis[v]=dis[now]+e[k].c-mid;
                    q[++r]=v;
                }
            }
        }
        int tail=r; l=1; r=0; int now=up;
        rep(i,1,tail){
            while (dep[q[i]]+now>=L&&now>=0){
                while (l<=r&&mx[now]>mx[dq[r]]) r--;
                dq[++r]=now;
                now--;
            }
            while (l<=r&&dep[q[i]]+dq[l]>U) l++;
            if (l<=r&&dis[q[i]]+mx[dq[l]]>=0) return 1;
        }
        rep(i,up+1,dep[q[tail]]) mx[i]=-inf;
        rep(i,1,tail) {
            int now=dep[q[i]];
            mx[now]=max(mx[now],dis[q[i]]);
        }
        up=max(up,dep[q[tail]]);
    }
    return 0;
}
void jud(int u){
    double l=ans,r=lim;
    while (r-l>=0.0001){
        double mid=(l+r)/2;
        if (go(u,mid)) l=mid;
        else r=mid;
    }
    ans=l;
}
void solve(int u){
    mn=inf;
    dfs(u,0);
    u=rt;
    jud(u);
    vis[u]=1;
     
    for (int j=head[u];j;j=e[j].pre){
        int v=e[j].obj;
        if (!vis[v]) {
            sum=s[v];
            if (sum>L) solve(v);
        }
    }
}
int main(){
    n=read();
    L=read(); U=read();
    int x,y; double z;
    rep(i,1,n-1){
        x=read(); y=read(); scanf("%lf",&z);
        insert(x,y,z);
        insert(y,x,z);
        lim=max(lim,z);
    }
    sum=n;
    solve(1);
    printf("%.3lf\n",ans);
    return 0;
}

BZOJ1758: [Wc2010]重建计划(01分数规划+点分治+单调队列)的更多相关文章

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

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

  2. [WC2010]重建计划(分数规划+点分治+单调队列)

    题目大意:给定一棵树,求一条长度在L到R的一条路径,使得边权的平均值最大. 题解 树上路径最优化问题,不难想到点分治. 如果没有长度限制,我们可以套上01分数规划的模型,让所有边权减去mid,求一条路 ...

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

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

  4. 【BZOJ 1758】【WC 2010】重建计划 分数规划+点分治+单调队列

    一开始看到$\frac{\sum_{}}{\sum_{}}$就想到了01分数规划但最终还是看了题解 二分完后的点分治,只需要维护一个由之前处理过的子树得出的$tb数组$,然后根据遍历每个当前的子树上的 ...

  5. [WC2010][BZOJ1758]重建计划-[二分+分数规划+点分治]

    Description 传送门 Solution 看到那个式子,显然想到分数规划...(不然好难呢) 然后二分答案,则每条边的权值设为g(e)-ans.最后要让路径长度在[L,U]范围内的路径权值&g ...

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

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

  7. BZOJ1758 WC2010 重建计划 二分答案、点分治、单调队列

    传送门 看到平均数最大,自然地想到二分答案.那么我们的$check$函数就是要求:是否存在一条长度在$[L,U]$的路径,满足其权值和$\geq 0$. 看到长度在$[L,U]$,自然地想到点分治求解 ...

  8. 2019.01.21 bzoj1758: [Wc2010]重建计划(01分数规划+长链剖分+线段树)

    传送门 长链剖分好题. 题意简述:给一棵树,问边数在[L,R][L,R][L,R]之间的路径权值和与边数之比的最大值. 思路: 用脚指头想都知道要01分数规划. 考虑怎么checkcheckcheck ...

  9. BZOJ1758: [Wc2010]重建计划

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

随机推荐

  1. iOS 判断数组array中是否包含元素a,取出a在array中的下标+数组方法详解

    目前找到来4个解决办法,第三个尤为简单方便 NSArray * arr = @["]; //是否包含 "]) { NSInteger index = [arr indexOfObj ...

  2. iOS Block的简单使用以及__block 和static修饰变量

    简单的代码总结,不足之处多多指教. //简单的使用 -(void)blockOne{ ; int(^BlockOne)(int) = ^(int num2) { return number*num2; ...

  3. SP的封装(数据持久化方式一)

    1.先看一段描述: Interface for accessing and modifying preference data returned by Context.getSharedPrefere ...

  4. 解题思路:house robber i && ii && iii

    这系列题的背景:有个小偷要偷钱,每个屋内都有一定数额的钱,小偷要发家致富在北京买房的话势必要把所有屋子的钱都偷了,但是屋子之内装了警报器,在一定条件下会触发朝阳群众的电话,所以小偷必须聪明一点,才能保 ...

  5. bzoj 3670: [Noi2014]动物园

    Description 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的真才实学向游客要吃的,园长决定开设算法班,让动物们学习 ...

  6. js计算字数

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  7. layer遮罩层 简单的遮罩层

    在这里提供一个简单layer遮罩层,想深入了解可以进入 layer官网 多多学习哦. 先看下HTML页面代码 <!DOCTYPE html> <html lang="en& ...

  8. centos 系统日志

    Linux系统日志主要有三类:连接时间日志.进程统计日志和错误日志 连接时间日志 连接时间日志由多个程序执行,把记录写入到/var/og/wtmp和/var/run/utmp.ogin等程序更新wtm ...

  9. sql查询化繁为简 告别rs.getString("XX"),bean属性赋值setXX("XX")

    一.在执行sql语句查询时候,查询的结果是set的map集合(ResultSet): 结果使用rs.getString("XX")获得对应属性的值,赋值到bean对象的相应的属性中 ...

  10. javascript中对象字面量与数组字面量

    第一部分 我们知道JavaScript中的数据类型有基本数据类型和引用类型,其中Object类型就是非常常用的类型.那么如果创建一个Object类型的实例呢?下面我介绍两种方法: 第一:构造函数法. ...