zoukankan      html  css  js  c++  java
  • [BZOJ 1758] [Wc2010]重建计划

    [Wc2010]重建计划

    BZOJ 1758

    参考博客

    https://blog.bill.moe/WC2010-rebuild/

    1

    题目大意

    给出一个 (n) 个节点带边权的树,要求找出一条边数在 ([L,U]) 之间的路径使得 (dfrac{sum_{ein S}e(w)}{|S|}) 最大

    数据范围

    (nle100000,1le Lle Ule n-1,V_ile1000000)

    时空限制

    40sec,128MB

    分析

    首先01分数规划转判断问题,现在我们每个边有新的边权,我们要求树上边权最大的一条边数 ([L,U]) 的路径

    因为与深度有关,可以使用长链剖分解决,现在要用线段树维护一个区间最值,那么之前的指针实现移位就无法使用了,考虑数组只会向右移位(转移方程为 (f(v,j)->f(u,j+1))),那么可以采用另一种移位方法,将树剖分成链,那么(f(u,j)) 的值就存储在 (val(dfn[u]+j)) 位置,对 (val) 数组维护一个线段树就好了

    Code

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    inline char nc() {
    	static char buf[100000], *l = buf, *r = buf;
    	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
    }
    template<class T> void read(T & x) {
    	x = 0; int f = 1, ch = nc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=nc();}
    	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=nc();}
    	x *= f; 
    }
    #define lson u << 1, l, mid
    #define rson u << 1 | 1, mid + 1, r
    const double eps = 1e-5;
    const double infty = 1e18;
    const int maxn = 100000 + 5;
    const int maxe = maxn * 2;
    const int maxv = 1000000 + 5;
    int N, L, U; double an;
    int head[maxn], ecnt;
    double mid;
    int dfn[maxn], len[maxn], son[maxn], cost[maxn], dfc;
    double r[maxn];
    struct edge {
    	int to, nex, cost;
    	edge(int to=0,int nex=0,int cost=0) : to(to), nex(nex), cost(cost) {}
    } G[maxe];
    struct segment_tree {
    	double mx[maxn << 2];
    	inline void pushup(int u) {
    		mx[u] = max(mx[u << 1], mx[u << 1 | 1]);
    	}
    	void build(int u, int l, int r) {
    		if(l == r) {
    			mx[u] = -infty;
    			return;
    		}
    		int mid = (l + r) >> 1;
    		build(lson), build(rson);
    		pushup(u);
    	}
    	void update(int u, int l, int r, int qp, double qv) {
    		if(l == r) {
    			mx[u] = max(mx[u], qv);
    			return;
    		}
    		int mid = (l + r) >> 1;
    		if(qp <= mid) update(lson, qp, qv);
    		else update(rson, qp, qv);
    		pushup(u);
    	}
    	double query(int u, int l, int r, int ql, int qr) {
    		if(l == ql && r == qr) {
    			return mx[u];
    		}
    		int mid = (l + r) >> 1;
    		if(qr <= mid) return query(lson, ql, qr);
    		else if (ql > mid) return query(rson, ql, qr);
    		else {
    			double L = query(lson, ql, mid);
    			double R = query(rson, mid + 1, qr);
    			return max(L, R);
    		}
    	}
    } seg;
    inline void addedge(int u, int v, int w) {
    	G[ecnt] = edge(v, head[u], w), head[u] = ecnt++;
    	G[ecnt] = edge(u, head[v], w), head[v] = ecnt++;
    }
    void dfs1(int u, int fa) {
    	son[u] = -1;
    	for(int i = head[u]; ~ i; i = G[i].nex) {
    		int v = G[i].to; if(v == fa) continue;
    		dfs1(v, u);
    		if(son[u] == -1 || len[son[u]] < len[v]) {
    			son[u] = v; cost[u] = G[i].cost;
    			len[u] = len[v] + 1;
    		}
    	}
    }
    void dfs2(int u, int fa) {
    	dfn[u] = ++dfc;
    	if(son[u] != -1) {
    		dfs2(son[u], u);
    	}
    	for(int i = head[u]; ~ i; i = G[i].nex) {
    		int v = G[i].to; if(v == fa || v == son[u]) continue;
    		dfs2(v, u);
    	}
    } 
    double query(int u, int l, int r) {
    	l = max(l, 0), r = min(r, len[u]);
    	if(l > r) return -infty;
    	return seg.query(1, 1, N, dfn[u] + l, dfn[u] + r);
    }
    void dp(int u, int fa, double dis) {
    	if(son[u] != -1) {
    		dp(son[u], u, dis + cost[u] - mid);
    	}
    	seg.update(1, 1, N, dfn[u], dis);
    	for(int i = head[u]; ~ i; i = G[i].nex) {
    		int v = G[i].to; if(v == fa || v == son[u]) continue;
    		dp(v, u, dis + G[i].cost - mid);
    		for(int j = 0; j <= len[v]; ++j) {
    			r[j] = seg.query(1, 1, N, dfn[v] + j, dfn[v] + j);
    			an = max(an, r[j] + query(u, L - j - 1, U - j - 1) - dis * 2);
    		}
    		for(int j = 0; j <= len[v]; ++j) {
    			seg.update(1, 1, N, dfn[u] + j + 1, r[j]);
    		}
    	}
    	an = max(an, query(u, L, U) - dis);
    }
    bool judge() {
    	an = -infty;
    	seg.build(1, 1, N);
    	dp(1, 0, 0);
    	return an > -eps;
    }
    double solve() {
    	double l = 0, r = maxv;
    	while(r - l > eps)
    	{
    		mid = (l + r) / 2;
    		if(judge()) l = mid;
    		else r = mid;
    	}
    	return l;
    }
    int main() {
    //	freopen("1.txt", "r", stdin);
    	read(N), read(L), read(U);
    	memset(head, -1, sizeof(head)); 
    	for(int i = 1; i < N; ++i) {
    		int A, B, V; read(A), read(B), read(V);
    		addedge(A, B, V);
    	}
    	dfs1(1, 0), dfs2(1, 0);
    	printf("%.3lf
    ", solve());
    	return 0;
    }
    
  • 相关阅读:
    直接插入排序
    归并排序
    正则问题
    九宫重排
    java合并两个集合并通过stream流构建响应结果
    企业微信扫码登录
    docker安装es
    docker安装nacos随记
    解决docker安装mysql8.0无法远程连接问题
    java分析工具10:jvm测试与调优
  • 原文地址:https://www.cnblogs.com/ljzalc1022/p/10250945.html
Copyright © 2011-2022 走看看