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

一开始看到$\frac{\sum_{}}{\sum_{}}$就想到了01分数规划但最终还是看了题解

二分完后的点分治,只需要维护一个由之前处理过的子树得出的$tb数组$,然后根据遍历每个当前的子树上的结点的深度来确定$tb数组$中的滑块。

因为分数规划要找的是$max$,BFS遍历当前结点的深度越来越大,这样滑块也是单调向右滑动,所以滑块里的最大值就应当用单调队列解决

#include<cstdio>
#include<algorithm>
#define read(x) x=getint()
#define N 100003
#define eps 0.0001
#define max(a,b) (a)>(b)?a:b
using namespace std;
inline int getint() {
    char c; int fh = 1, k = 0;
    for( ; c < ‘0‘ || c > ‘9‘; c = getchar()) if ( c == ‘-‘) fh = -1;
    for( ; c >= ‘0‘ && c <= ‘9‘; c = getchar()) k = k * 10 + c - ‘0‘;
    return k * fh;
}
struct node {
    int nxt, to, w;
} E[N << 1];
bool vis[N];
double ans = 0.0, limi = 0.0, dis[N], tb[N];
int sz[N], n, cnt = 0, L, U, point[N], root, rtm = N, fa[N], q[N], dq[N], deep[N];
inline void ins( int x, int y, int z) {++cnt; E[cnt].nxt = point[x]; E[cnt].to = y; E[cnt].w = z; point[x] = cnt;}
inline void fdrt( int x, int fa, int s) {
    sz[x] = 1;
    int ma = 0;
    for( int tmp = point[x]; tmp; tmp = E[tmp].nxt)
        if ( !vis[E[tmp].to] && E[tmp].to != fa) {
            fdrt( E[tmp].to, x, s);
            sz[x] += sz[E[tmp].to];
            ma = max( ma, sz[E[tmp].to]);
        }
    ma = max( ma, s - ma);
    if ( ma < rtm) {
        rtm = ma;
        root = x;
    }
}
inline bool can( int x, double M) {
    int le = 0, head, tail, h, t, now;
    for( int tmp = point[x]; tmp; tmp = E[tmp].nxt)
        if ( !vis[E[tmp].to]) {
            head = 0;
            tail = 1;
            q[0] = E[tmp].to;
            fa[E[tmp].to] = x;
            deep[E[tmp].to] = 1;
            dis[E[tmp].to] = (double) E[tmp].w - M;
            while ( head != tail) {
                now = q[head];
                ++head; if ( head >= N) head %= N;
                for( int i = point[now]; i; i = E[i].nxt)
                    if ( !vis[E[i].to] && E[i].to != fa[now]) {
                        q[tail] = E[i].to;
                        fa[E[i].to] = now;
                        deep[E[i].to] = deep[now] + 1;
                        dis[E[i].to] = dis[now] + (double) E[i].w - M;
                        ++tail; if ( tail >= N) tail %= N;
                    }
            }
            h = 1;
            t = 0;
            now = le;
            for( int i = 0; i < tail; ++i) {
                while ( deep[q[i]] + now >= L && now >= 0) {
                    while ( h <= t && tb[dq[t]] < tb[now])
                        --t;
                    dq[++t] = now;
                    --now;
                }
                while ( h <= t && deep[q[i]] + dq[h] > U)
                    ++h;
                if ( h <= t && dis[q[i]] + tb[dq[h]] >= 0)
                    return 1;
            }
            for( int i = le + 1; i <= deep[q[tail-1]]; ++i)
                tb[i] = -1E9;
            for( int i = 0; i < tail; ++i)
                tb[deep[q[i]]] = max( tb[deep[q[i]]], dis[q[i]]);
            le = max( le, deep[q[tail-1]]);
        }
    return 0;
}
inline void work( int x) {
    double left = ans, right = limi, mid;
    while ( right - left > eps) {
        mid = ( left + right) / 2;
        if ( can ( x, mid))
            left = mid;
        else
            right = mid;
    }
    ans = left;
}
inline void dfs( int x, int s) {
    vis[x] = 1;
    work( x);
    for( int tmp = point[x]; tmp; tmp = E[tmp].nxt)
        if ( !vis[E[tmp].to]) {
            rtm = N;
            int ss = sz[E[tmp].to] < sz[x] ? sz[E[tmp].to] : s - sz[x];
            fdrt( E[tmp].to, -1, ss);
            if ( sz[E[tmp].to] > L)
                dfs( root, ss);
        }
}
int main() {
    read(n); read(L); read(U);
    int a, b, c;
    for( int i = 1; i < n; ++i) {
        read(a); read(b); read(c);
        ins( a, b, c);
        ins( b, a, c);
        limi = max( limi, c);
    }
    fdrt( 1, -1, n);
    dfs( 1, n);
    printf( "%.3lf\n", ans);
    return 0;
}

这样就可以了

时间: 2024-12-05 00:18:39

【BZOJ 1758】【WC 2010】重建计划 分数规划+点分治+单调队列的相关文章

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

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进行标

[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

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

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

BZOJ.4753.[JSOI2016]最佳团体(01分数规划 树形背包DP)

题目链接 \(Description\) 每个点有费用si与价值pi,要求选一些带根的连通块,总大小为k,使得 \(\frac{∑pi}{∑si}\) 最大 \(Solution\) 01分数规划,然后dp,设f[i][j]表示i子树选j个的最大权值和,直接暴力背包转移即可 在枚举子节点选的数量时,假设x有1.2.3.4四个子节点,复杂度为 \(1*sz[1]+sz[1]*sz[2]+(sz[1]+sz[2])*sz[3]+(sz[1]+sz[2]+sz[3])*sz[4]\) 相当于每对点在L

bzoj 3232: 圈地游戏【分数规划+最小割】

数组开小导致TTTTTLE-- 是分数规划,设sm为所有格子价值和,二分出mid之后,用最小割来判断,也就是判断sm-dinic()>=0 这个最小割比较像最大权闭合子图,建图是s像所有点连流量为格子价值的边(相当于最大权闭合子图中的正权点),然后考虑边缘,两个相邻的格子,如果一个选一个不选那么中间这条边就有负的贡献,所以两个相邻的格子之间连两条边权为mid*边权的边,注意是两条,要互相连一下,然后所有边界上的点像t连边权为mid*边界边权的边,相当于假装外面还有一层点全标为t,然后跑最小割判断

【BZOJ 2806】 2806: [Ctsc2012]Cheat (SAM+二分+DP+单调队列)

2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1262  Solved: 643 Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库的行数接下来M行的01串,表示标准作文库接下来N行的01串,表示N篇作文 Output N行,每行一个整数,表示这篇作文的Lo 值. Sample Input 1 2 10110 000001110 1011001100 Sam

【待填坑】bzoj上WC的题解

之前在bzoj上做了几道WC的题目,现在整理一下 bzoj2115 去膜拜莫队的<高斯消元解xor方程组> bzoj2597 LCT维护MST bzoj1758 分数规划+树分治+单调队列 bzoj2595 斯坦纳树,一类用spfa转移的dp,具体可以膜拜<spfa算法的优化及应用>(我是不会插头的蒟蒻) bzoj2597 补集思想之后就变成了显然的平方流 bzoj3052 树上带修改莫队算法(如果一无所知的话,可以按2038 1086 3757 3052的顺序做) bzoj145