题目大意:给你n个区间,你要划分成若干段,使得每段交非空,以及每段收益是C(长度,2)。求最大收益。
n
≤
3
×
1
0
5
n\le3\times10^5
n≤3×105
题解:显然dp,斜率游化,然后发现每个点贡献的是一段区间,询问的横坐标就是下标,因此直接区间李超线段树即可。
#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 gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
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;
}
const int N=300010;const lint inf=LLONG_MIN/10;
int l[N],r[N],R[N];lint dp[N];
namespace GETR{
struct segment{
int l,r,v,pt;
segment *ch[2];
}*rt;
inline int build(segment* &rt,int l,int r)
{
rt=new segment,rt->l=l,rt->r=r,rt->v=rt->pt=0;
int mid=(l+r)>>1;if(l==r) return 0;
return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r);
}
inline int update_tags(segment* &rt,int v) { return rt->v+=v,rt->pt+=v; }
inline int push_down(segment* &rt) { rep(i,0,1) update_tags(rt->ch[i],rt->pt);return rt->pt=0; }
inline int update(segment* &rt,int s,int t,int v)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(s<=l&&r<=t) return update_tags(rt,v);
if(rt->pt) push_down(rt);
if(s<=mid) update(rt->ch[0],s,t,v);
if(mid<t) update(rt->ch[1],s,t,v);
return rt->v=max(rt->ch[0]->v,rt->ch[1]->v);
}
inline int getR(int n)
{
int mxr=0;rep(i,1,n) mxr=max(mxr,r[i]);
build(rt,1,mxr);
for(int i=n,j=n;i;i--)
{
update(rt,l[i],r[i],1);
while(rt->v!=j-i+1) update(rt,l[j],r[j],-1),j--;
R[i]=j;
}
return 0;
}
}
struct Line{
lint k,b;Line(lint _k=0,lint _b=inf) { k=_k,b=_b; }
inline lint operator()(int x) { return k*x+b; }
};
struct segment{
int l,r;Line F;
segment *ch[2];
}*rt;
inline int build(segment* &rt,int l,int r)
{
rt=new segment,rt->l=l,rt->r=r;int mid=(l+r)>>1;if(l==r) return 0;
return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r);
}
inline int ins(segment* &rt,Line F)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(F(l)>rt->F(l)) swap(F,rt->F);
if(F(r)<=rt->F(r)) return 0;
if(F(mid)<=rt->F(mid)) ins(rt->ch[1],F);
else swap(F,rt->F),ins(rt->ch[0],F);
return 0;
}
inline int update(segment* &rt,int s,int t,Line F)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(s<=l&&r<=t) return ins(rt,F);
if(s<=mid) update(rt->ch[0],s,t,F);
if(mid<t) update(rt->ch[1],s,t,F);
return 0;
}
inline lint query(segment* &rt,int p)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
lint v=rt->F(p);if(l==r) return v;
return max(v,query(rt->ch[p>mid],p));
}
int main()
{
// freopen("data.in","r",stdin);
int n=inn();
rep(i,1,n) l[i]=inn(),r[i]=inn()-1;
GETR::getR(n),build(rt,1,n);
update(rt,1,R[1],Line(0,0));
rep(i,1,n)
{
dp[i]=query(rt,i)+i*(i-1ll)/2;
if(i<n) update(rt,i+1,R[i+1],Line(-i,dp[i]+i*(i+1ll)/2));
}
return !printf("%lld\n",dp[n]);
}