zoukankan      html  css  js  c++  java
  • 洛谷 P3994 高速公路(斜率优化)

    题目链接

    题意:给出一棵树,(1) 号点为根,边上有边权。
    每个点有两个参数 (p_i,q_i)
    如果你想从 (i) 号点到与其距离为 (d)(j) 号点,那么你需花费 (d imes p_i+q_i)
    对于每个 (i in [2,n]),求出:假设你站在 (i) 号点,到达 (1) 号点的最小花费。
    (1 leq n leq 10^6)

    树上斜率优化
    dfs 求出 (i) 到根节点的路径长度为 (d_i)
    朴素的 (dp) 非常容易。设 (dp_i) 表示到达 (i) 号点的最小花费。那么显然

    [dp_i=min{dp_j+(d_i-d_j) imes p_i+q_i} ]

    假设 (j)(k) 的下方,那么 (j)(k) 更优当且仅当:

    [dp_j+(d_i-d_j) imes p_i+q_i<dp_k+(d_i-d_k) imes p_i+q_i ]

    [dp_j-d_j imes p_i<dp_k-d_k imes p_i ]

    [dp_j-dp_k<(d_j-d_k) imes p_i ]

    [frac{dp_j-dp_k}{d_j-d_k}<p_i ]

    开个队列维护 (i) 的祖先的点组成的下凸包,然后在队列里二分斜率就可以了。

    /*
    Contest: -
    Problem: P3994
    Author: tzc_wk
    Time: 2020.5.29
    */
    #include <bits/stdc++.h>
    using namespace std;
    #define fi			first
    #define se			second
    #define fz(i,a,b)	for(int i=a;i<=b;i++)
    #define fd(i,a,b)	for(int i=a;i>=b;i--)
    #define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
    #define all(a)		a.begin(),a.end()
    #define giveup(...) return printf(__VA_ARGS__),0;
    #define fill0(a)	memset(a,0,sizeof(a))
    #define fill1(a)	memset(a,-1,sizeof(a))
    #define fillbig(a)	memset(a,0x3f,sizeof(a))
    #define fillsmall(a) memset(a,0xcf,sizeof(a))
    #define mask(a)		(1ll<<(a))
    #define maskx(a,x)	((a)<<(x))
    #define _bit(a,x)	(((a)>>(x))&1)
    #define _sz(a)		((int)(a).size())
    #define filei(a)	freopen(a,"r",stdin);
    #define fileo(a)	freopen(a,"w",stdout);
    #define fileio(a) 	freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    #define eprintf(...) fprintf(stderr,__VA_ARGS__)
    #define put(x)		putchar(x)
    #define eoln        put('
    ')
    #define space		put(' ')
    #define y1			y1010101010101
    #define y0			y0101010101010
    #define int long long
    typedef pair<int,int> pii;
    inline int read(){
    	int x=0,neg=1;char c=getchar();
    	while(!isdigit(c)){
    		if(c=='-')	neg=-1;
    		c=getchar();
    	}
    	while(isdigit(c))	x=x*10+c-'0',c=getchar();
    	return x*neg;
    }
    inline int qpow(int x,int e,int _MOD){
    	int ans=1;
    	while(e){
    		if(e&1)	ans=ans*x%_MOD;
    		x=x*x%_MOD;
    		e>>=1;
    	}
    	return ans;
    }
    int n=read();
    vector<pii> g[1000005];
    int p[1000005],q[1000005],dep[1000005],dp[1000005];
    int dq[1000005],hd=1,tl=0;
    inline double sl(int j,int k){
    	return 1.0*(dp[k]-dp[j])/(dep[k]-dep[j]);
    }
    inline int bsearch(double slo){
    	if(hd==tl)	return dq[hd];
    	int l=hd,r=tl-1,ans=tl;
    	while(l<=r){
    		int mid=(l+r)>>1;
    		if(sl(dq[mid],dq[mid+1])>=slo)	ans=mid,r=mid-1;
    		else							l=mid+1;
    	}
    	return dq[ans];
    }
    inline void dfs(int x){
    	int y=bsearch(p[x]);
    	int curhd=hd,curtl=tl;
    	dp[x]=dp[y]+(dep[x]-dep[y])*p[x]+q[x];
    	while(hd<tl&&sl(dq[tl],dq[tl-1])>sl(dq[tl],x))	tl--;
    	int curq=dq[++tl];
    	dq[tl]=x;
    	foreach(it,g[x]){
    		int z=it->first,s=it->second;
    		dep[z]=dep[x]+s;
    		dfs(z);
    	}
    	hd=curhd,dq[tl]=curq,tl=curtl;
    }
    signed main(){
    	fz(i,2,n){
    		int f=read(),s=read();
    		p[i]=read(),q[i]=read();
    		g[f].push_back({i,s});
    	}
    	dfs(1);
    	fz(i,2,n)	cout<<dp[i]<<endl;
    	return 0;
    }
    
  • 相关阅读:
    如何实现对ELK各组件的监控?试试Metricbeat
    Dubbo日志链路追踪TraceId选型
    Spring Security如何优雅的增加OAuth2协议授权模式
    聊一聊:MyBatis和Spring Data JPA的选择问题
    Java微服务 vs Go微服务,究竟谁更强!?
    你一定需要知道的高阶JAVA枚举特性!
    当音乐学博士搞起编程,用一本书改变了Java世界!
    Spring Boot 2.x基础教程:使用Flyway管理数据库版本
    文件上传的单元测试怎么写?
    Spring Boot 2.x基础教程:多个文件的上传
  • 原文地址:https://www.cnblogs.com/ET2006/p/12988873.html
Copyright © 2011-2022 走看看