见面会 - dp - 斜率优化 - 李超线段树

题目大意:给你n个区间,你要划分成若干段,使得每段交非空,以及每段收益是C(长度,2)。求最大收益。 n ≤ 3 × 1 0 5 n\le3\times10^5 n3×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]);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值