党² - 李超线段树

题目大意:给你两个大小为n的三元组集合 S 1 = { ( L i , R i , v i ) ∣ i ∈ [ 1 , n ] } S_1=\{(L_i,R_i,v_i)|i\in[1,n]\} S1={(Li,Ri,vi)i[1,n]} S 2 = { ( A i , B i , c i ) ∣ i ∈ [ 1 , n ] } S_2=\{(A_i,B_i,c_i)|i\in[1,n]\} S2={(Ai,Bi,ci)i[1,n]},你要选出 ( L , R , v ) ∈ S 1 , ( A , B , c ) ∈ S 2 (L,R,v)\in S_1,(A,B,c)\in S_2 (L,R,v)S1,(A,B,c)S2,使得 ( r − l + 1 ) v c (r-l+1)vc (rl+1)vc最小,其中 [ l , r ] [l,r] [l,r]表示 [ L , R ] [L,R] [L,R] [ A , B ] [A,B] [A,B]的交集。 R , B , n ≤ 1 0 5 R,B,n\le10^5 R,B,n105
题解:
首先一个区间包含另一个的情况可以直接扫描线求。
否则枚举 ( A , B , c ) (A,B,c) (A,B,c),不妨设某个 ( L , R , v ) (L,R,v) (L,R,v)满足 L ≤ A ≤ R ≤ B L\le A\le R\le B LARB,那么算出来是 ( R + 1 − A ) v c = c [ ( − v ) A + ( R + 1 ) v ] (R+1-A)vc=c[(-v)A+(R+1)v] (R+1A)vc=c[(v)A+(R+1)v],相当于每个 ( L , R , v ) (L,R,v) (L,R,v)维护一条线段,当 x ∈ [ L , R ] x\in[L,R] x[L,R]时能够取到 ( − v ) x + ( R + 1 ) v (-v)x+(R+1)v (v)x+(R+1)v的函数值。这是一个经典的李超树问题。

#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=100010;const int m=1e5;
int L[N],R[N],v[N],A[N],B[N],c[N];
struct P{
    int l,r,v;P(int _l=0,int _r=0,int _v=0) { l=_l,r=_r,v=_v; }
    inline bool operator<(const P &p)const { return r<p.r; }
}p[N],q[N];
namespace CONT_space{
    struct segment{
        int l,r;lint v;
        segment *ch[2];
    }*rt;
    inline int build(segment* &rt,int l,int r)
    {
        rt=new segment,rt->l=l,rt->r=r,rt->v=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(segment* &rt,int p,lint v)
    {
        int l=rt->l,r=rt->r,mid=(l+r)>>1;rt->v=max(rt->v,v);
        if(l==r) return 0;return update(rt->ch[p>mid],p,v);
    }
    inline lint query(segment* &rt,int s,int t)
    {
        int l=rt->l,r=rt->r,mid=(l+r)>>1;
        if(s<=l&&r<=t) return rt->v;lint ans=0;
        if(s<=mid) ans=max(ans,query(rt->ch[0],s,t));
        if(mid<t) ans=max(ans,query(rt->ch[1],s,t));
        return ans;
    }
    inline lint cont(int n)
    {
        rep(i,1,n) p[i]=P(L[i],R[i],v[i]),q[i]=P(A[i],B[i],c[i]);
        sort(p+1,p+n+1),sort(q+1,q+n+1);lint ans=0;build(rt,1,m);
        for(int i=1,j=0;i<=n;i++)
        {
            int a=q[i].l,b=q[i].r;
            while(j<n&&p[j+1].r<=b) j++,update(rt,p[j].l,(p[j].r-p[j].l+1ll)*p[j].v);
            ans=max(ans,query(rt,a,b)*q[i].v);
        }
        return ans;
    }
}using CONT_space::cont;
namespace SOLVE_space{
    const lint inf=-1e16;
    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 L;
        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 update(segment* &rt,Line L)
    {
        int l=rt->l,r=rt->r,mid=(l+r)>>1;
        if(rt->L(l)<L(l)) swap(rt->L,L);
        if(rt->L(r)>=L(r)) return 0;
        if(rt->L(mid)>=L(mid)) update(rt->ch[1],L);
        else swap(rt->L,L),update(rt->ch[0],L);
        return 0;
    }
    inline int update(segment* &rt,int s,int t,const Line &L)
    {
        int l=rt->l,r=rt->r,mid=(l+r)>>1;
        if(s<=l&&r<=t) return update(rt,L);
        if(s<=mid) update(rt->ch[0],s,t,L);
        if(mid<t) update(rt->ch[1],s,t,L);
        return 0;
    }
    inline lint query(segment* &rt,int p)
    {
        int l=rt->l,r=rt->r,mid=(l+r)>>1;lint ans=rt->L(p);
        if(l==r) return ans;return max(ans,query(rt->ch[p>mid],p));
    }
    inline lint solve(int n)
    {
        rep(i,1,n) p[i]=P(L[i],R[i],v[i]),q[i]=P(A[i],B[i],c[i]);
        sort(p+1,p+n+1),sort(q+1,q+n+1);lint ans=0;build(rt,1,m);
        for(int i=1,j=0;i<=n;i++)
        {
            while(j<n&&p[j+1].r<=q[i].r)
                j++,update(rt,p[j].l,p[j].r,Line(-p[j].v,p[j].v*(p[j].r+1ll)));
            lint res=query(rt,q[i].l);if(res>0) ans=max(ans,res*q[i].v);
        }
        return ans;
    }
}using SOLVE_space::solve;
#define rev(x) x=m-x+1
int main()
{
    int n=inn();
    rep(i,1,n) L[i]=inn(),R[i]=inn(),v[i]=inn();
    rep(i,1,n) A[i]=inn(),B[i]=inn(),c[i]=inn();
    lint ans=max(cont(n),solve(n));
    rep(i,1,n) swap(L[i],A[i]),swap(B[i],R[i]),swap(v[i],c[i]);
    ans=max(ans,max(cont(n),solve(n)));
    return !printf("%lld\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值