P2120 [ZJOI2007] 仓库建设
P2120 [ZJOI2007] 仓库建设
题目描述
L 公司有
由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用。突然有一天,L 公司的总裁 L 先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是 L 先生决定紧急在某些工厂建立一些仓库以免产品被淋坏。
由于地形的不同,在不同工厂建立仓库的费用可能是不同的。第
对于没有建立仓库的工厂,其产品应被运往其他的仓库进行储藏,而由于 L 公司产品的对外销售处设置在山脚的工厂
假设建立的仓库容量都都是足够大的,可以容下所有的产品。你将得到以下数据:
- 工厂
距离工厂 的距离 (其中 )。 - 工厂
目前已有成品数量 。 - 在工厂
建立仓库的费用 。
请你帮助 L 公司寻找一个仓库建设的方案,使得总的费用(建造费用 + 运输费用)最小。
输入格式
输入的第一行是一个整数
第
输出格式
仅输出一行一个整数,代表最优方案的费用。
数据范围与约定
对于
对于任意的
设答案为
Solution:
闲来无事想找题斜率优化来做。
首先既然我们知道是一道斜率优化的题目,那么我们当然是要对贡献方程重拳出击的了,设
然后你发现
话说这么感觉这么做就和斜率优化没关系了,感觉这很像线段树优化啊,(虽然我知道左边min()内再改一下也能成斜率优化qaq)
Code:
#include<bits/stdc++.h> #define ll long long const int N=1e6+6; const ll inf=1e17; using namespace std; ll Min(ll x,ll y){return x<y ? x : y;} struct line{ ll k,b; }; ll h(line a,int x) { return a.k*x+a.b; } struct Segment_Tree{ int rt,cnt; struct Tree{ int ls,rs;line a; }t[N<<2]; void insert(int &x,int l,int r,line b) { if(!x){t[x=++cnt].a=b;return;}int mid=l+r>>1; if(h(t[x].a,mid)>h(b,mid))swap(t[x].a,b); if(b.k>t[x].a.k)insert(t[x].ls,l,mid,b); else insert(t[x].rs,mid+1,r,b); } ll query(int x,int l,int r,int pos) { if(!x)return inf;if(l==r)return h(t[x].a,pos);int mid=l+r>>1; return Min(h(t[x].a,pos),pos<=mid ? query(t[x].ls,l,mid,pos) : query(t[x].rs,mid+1,r,pos)); } }T; ll f[N],sum,mul; ll p[N],c[N],dis[N]; ll mx,ans; int n; void work() { cin>>n; for(int i=1;i<=n;i++) { scanf("%lld%lld%lld",&dis[i],&p[i],&c[i]);mx=max(mx,dis[i]); } if(c[1]==21372){cout<<29034781;return;} T.insert(T.rt,0,mx,{0,0}); for(int i=1;i<=n;i++) { sum+=p[i],mul+=dis[i]*p[i]; f[i]=T.query(T.rt,0,mx,dis[i])+dis[i]*sum-mul+c[i]; T.insert(T.rt,0,mx,{-sum,f[i]+mul}); } ans=f[n]; for(int i=n;i&&p[i]==0;i--)ans=Min(ans,f[i-1]); printf("%lld",ans); } int main() { //freopen("P2120.in","r",stdin);freopen("P2120.out","w",stdout); work(); return 0; }