【模板变形】凸壳二分+斜率优化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<<'
';
} 
原文地址:https://www.cnblogs.com/zsben991126/p/12521332.html