传送门
- 思路:预处理,每一个 是 单增 单减的,那么考虑 之间的转移 
 我们考虑两个决策点,其中 为最优决策点,那么 
 注意到这是个斜率为正的斜线,而当前转移的又是类似反比例形状的,那么最优决策点一定会将转移点分成两部分,那么这个就可以通过分治来解决了 
 下面来考虑的限制,发现对应的是一段区间,那么我们线段树分治,每个结点做一次决策单调性 即可, 
#include<bits/stdc++.h>
#define cs const
#define fi first
#define se second
#define pb push_back
using namespace std;
namespace IO{
    cs int Rlen=1<<22|1;
    inline char gc(){
        static char buf[Rlen],*p1,*p2;
        (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin));
        return p1==p2?EOF:*p1++;
    }
    int read(){
        int x=0; char c=gc(); bool f=false;
        while(!isdigit(c)) f=(c=='-'),c=gc();
        while(isdigit(c)) x=(((x<<2)+x)<<1)+(c^48), c=gc();
        return f?-x:x;
    }
} using namespace IO;
cs int N = 1e6 + 50;
typedef long long ll;
cs ll INF = 1e16;
typedef pair<int, int> pi;
int n, m; pi a[N]; ll f[N];
vector<int> S[N]; int c[N];
void add(int x, int v){ assert(x<=m); for(;x<=m;x+=x&-x) c[x]=max(c[x],v); }
int ask(int x){ int as=0; for(;x;x-=x&-x) as=max(as,c[x]); return as; }
namespace cdq{
    vector<int> A, B;
    void work(int l, int r, int L, int R){
        if(l>r) return;
        int mid=(l+r)>>1, ps=A[mid], trs=0; ll now=INF;
        for(int i=L; i<=R; i++){
            assert(a[ps].fi > a[B[i]].fi);
            assert(a[ps].se > a[B[i]].se);
            ll x = a[ps].se-a[B[i]].se, y = a[ps].fi-a[B[i]].fi;
            if(f[B[i]] + x * y < now) now = f[B[i]] + x * y, trs=i;
        } f[ps]=min(f[ps],now); 
        work(l,mid-1,trs,R); work(mid+1,r,L,trs);
    }
}
namespace SGT{
    cs int N = ::N << 2;
    vector<int> S[N];
    #define mid ((l+r)>>1)
    vector<int> now;
    void clr(int x, int l, int r){ 
        S[x].clear(); if(l==r) return; 
        clr(x<<1,l,mid); clr(x<<1|1,mid+1,r);
    }
    void ins(int x, int l, int r, int c){
        if(a[now[l]].se <= a[c].se && a[now[r]].fi <= a[c].fi){
            S[x].pb(c); return;
        } if(a[now[r]].se >= a[c].se) return;
        if(a[now[l]].fi >= a[c].fi) return;
        ins(x<<1,l,mid,c); ins(x<<1|1,mid+1,r,c);
    }
    void work(int x, int l, int r){
        if(S[x].size()) cdq::A=S[x], cdq::work(0,S[x].size()-1,l,r);
        if(l==r) return; work(x<<1,l,mid); work(x<<1|1,mid+1,r);
    } 
    #undef mid
}
int main(){
    #ifdef FSYolanda
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    #endif 
    n=read(), m=read(); 
    for(int i=1; i<=n; i++) a[i].fi=read(), a[i].se=read();
    a[++n]=pi(m,m); sort(a+1,a+n+1); int MAX=0;
    for(int i=1,x; i<=n; i++)
    x=ask(a[i].se-1)+1, MAX=max(MAX,x), add(a[i].se,x), S[x].pb(i);
    memset(f,0x3f,sizeof(f)); f[0]=0;
    for(int c : S[1]) f[c] = (ll)a[c].fi * a[c].se;
    for(int i=2; i<=MAX; i++){
        SGT::clr(1,0,S[i-1].size()-1); SGT::now=cdq::B=S[i-1];
        for(int c : S[i]) SGT::ins(1,0,S[i-1].size()-1,c);
        SGT::work(1,0,S[i-1].size()-1);
    } cout<<f[n]; return 0;
}
}                
                










