【模板变形】凸壳二分+斜率优化dp——cf1083E
由于斜率不是递增的,所以凸壳队列的head就不能动(退化成了一个单调栈),然后每次二分找直线切到的点
#include<bits/stdc++.h> using namespace std; #define N 2000006 #define ll long long struct point{ ll x,y; point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};} point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};} }; ll cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;} double slope(point k1,point k2){return 1.0*(k1.y-k2.y)/(k1.x-k2.x);} point q[N]; int head,tail; ll find(ll k){//凸壳上最右边的斜率>=k的点 if(tail==1)return 1; ll L=2,R=tail,mid,ans=1; while(L<=R){ mid=L+R>>1; if(slope(q[mid],q[mid-1])>=k) L=mid+1,ans=mid; else R=mid-1; } return ans; } void push(point k){//维护一个上凸壳 while(tail>1 && slope(q[tail],q[tail-1])<=slope(k,q[tail-1])) tail--; q[++tail]=k; } struct Node{ll x,y,a;}p[N]; int cmp(Node a,Node b){ if(a.x==b.x)return a.y<b.y; return a.x<b.x; } ll n,dp[N]; int main(){ cin>>n; for(int i=1;i<=n;i++) scanf("%lld%lld%lld",&p[i].x,&p[i].y,&p[i].a); sort(p+1,p+1+n,cmp); head=tail=1; q[1]=(point){0,0}; ll ans=0; for(int i=1;i<=n;i++){ ll pos=find(p[i].y);//寻找上凸壳里的点 dp[i]=q[pos].y-q[pos].x*p[i].y-p[i].a+p[i].x*p[i].y; push((point){p[i].x,dp[i]}); ans=max(ans,dp[i]); } cout<<ans<<'\n'; }