题目大意:参考这篇blog,但是数据范围是1e7。
题解:这题居然有线性做法是真的秀……
就是这个题不能直接线性的原因是斜率优化没办法支持删除信息,因此需要用分治/线段树等来去掉删除。
然后有一个黑科技:
考虑将序列划分为若干段,使得不存在一个转移区间同时和至少三个段有交。
划分方法是,由于转移区间端点是不降的,因此就是从左端点开始能向右就向右,可以发现这样划分是正确的。
这样有什么好处呢?会发现一个转移区间是由一段的后缀和一段的前缀拼起来的!
然后就可以分开转移,每一种情况都可以线性。然后这个题就线性了。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
namespace INPUT_SPACE{
const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;inline int gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
inline int inn() { int x,ch;while((ch=gc())<'0'||ch>'9');x=ch^'0';while((ch=gc())>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; }
}using INPUT_SPACE::inn;
const int N=300010;const lint inf=LLONG_MIN/100;const db eps=1e-9;
int vl[N],vr[N],L[N];
namespace GETL{
int sl[N],sr[N];
inline int getL(int n)
{
int hl=1,hr=1,tl=0,tr=0,j=1;
rep(i,1,n)
{
while(tl>=hl&&vl[i]>=vl[sl[tl]]) tl--;sl[++tl]=i;
while(tr>=hr&&vr[i]<=vr[sr[tr]]) tr--;sr[++tr]=i;
while(vl[sl[hl]]>vr[sr[hr]]) hl+=(sl[hl]==j),hr+=(sr[hr]==j),j++;
L[i]=j-1;
}
return 0;
}
}
inline int dcmp(db x) { return (x<-eps)?-1:(x>eps); }
struct Line{
lint k,b;Line(lint _k=0,lint _b=inf) { k=_k,b=_b; }
inline lint operator()(lint x)const { return k*x+b; }
inline db getis(const Line &L)const { return -((db)b-L.b)/(k-L.k); }
};
struct Queue{
int t;Line f[N];inline int clear() { return t=0; }
inline int add(Line F) { while(t>1&&dcmp(F.getis(f[t])-f[t].getis(f[t-1]))>=0) t--;f[++t]=F;return 0; }
inline lint query(lint x) { if(!t) return inf;while(t>1&&f[t](x)<=f[t-1](x)) t--;return f[t](x); }
}q;int l[N],r[N];lint f[N];
int main()
{
int n=inn(),bc=0;rep(i,1,n) vl[i]=inn(),vr[i]=inn()-1;GETL::getL(n);
for(int i=0,j=0;i<n;i=++j) { while(j+1<n&&L[j+2]<=i) j++;l[++bc]=i,r[bc]=j; }
f[0]=0;rep(i,1,n) f[i]=inf;
rep(i,1,bc)
{
q.clear();int k=l[i];
for(int j=r[i]+1;j>l[i];j--)
{
while(k>L[j]) k--,q.add(Line(k,f[k]+k*(k+1ll)/2));
f[j]=max(f[j],q.query(-j)+j*(j-1ll)/2);
}
q.clear();
rep(j,l[i]+1,r[i]+1) q.add(Line(-(j-1),f[j-1]+(j-1ll)*j/2)),f[j]=max(f[j],q.query(j)+j*(j-1ll)/2);
}
return !printf("%lld\n",f[n]);
}