数对

百般思念 提交于 2019-12-02 19:00:23

题解

算是历史遗留问题的解决

之前队长快跑看题解很迷糊,觉得似懂非懂的,AC但是很水,最后代码都不是我的,是$王_{drink_{grass}}$的

现在总算会了

首先题目中条件就是$max(a)<=b_i$

暴力dp就是$f[i][j]$表示考虑了前$i$个位置最大值为$j$时权值最大是多少

于是分情况讨论

1.$a_i>b_i$

因为要满足$max(a)<=b_i$所以$f[i][a[i]]=max(f[i-1][1],f[i-1][2],,,,,f[i-1][b[i]])+val$这些位置最大值都会改变为$a[i]$

2.$a_i<b_i$

因为要满足$max(a)<=b_i$显然在$a_i--b_i$之间$f[i-1][a[i]]--f[i-1][b[i]]$之间最大值不会变直接+val即可

在$1--a_{i-1}$,最大值变为$a[i]$,于是就有了$f[i][a[i]]=max(f[i-1][1],f[i-1][2],,,,,f[i-1][a[i-1]])+val$

可以用线段树维护

$f[i][a[i]]=max(f[i-1][1],f[i-1][2],,,,,f[i-1][b[i]])+val$

 

$f[i][a[i]]=max(f[i-1][1],f[i-1][2],,,,,f[i-1][a[i-1]])+val$

 

就是区间最大值,单点赋值

$f[i-1][a[i]]+val--f[i-1][b[i]]+val$

 

就是区间+

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define A 12000000
ll lsh[A];
ll n,maxn,len=0,cnt=0,q;
struct node{
    ll a,b,w;
    friend bool operator < (const node &c,const node &d){
        return ((c.a+c.b)==(d.a+d.b))?(c.b<d.b):((c.a+c.b)<(d.a+d.b));
    }
}s[A];
struct tree{
    ll l,r,f,val;
}tr[A];
void up(ll x){
    tr[x].val=max(tr[x<<1].val,tr[x<<1|1].val);
}
void down(ll x){
    tr[x<<1].f+=tr[x].f;
    tr[x<<1|1].f+=tr[x].f;
    tr[x<<1].val+=tr[x].f;
    tr[x<<1|1].val+=tr[x].f;
    tr[x].f=0;
}
void built(ll x,ll l,ll r){
    tr[x].l=l,tr[x].r=r;
    if(tr[x].l==tr[x].r){
        tr[x].val=0;
        return ;
    }
    ll mid=(l+r)>>1;
    built(x<<1,l,mid);
    built(x<<1|1,mid+1,r);
    up(x);
}
void seg_max(ll x,ll l,ll r){
    if(l>r) return;
    if(tr[x].f) down(x);
    if(tr[x].l>=l&&tr[x].r<=r){
        maxn=max(maxn,tr[x].val);
//        maxn=tr[x].val;
        return ;
    }    
    ll mid=(tr[x].l+tr[x].r)>>1;
    if(mid>=l) seg_max(x<<1,l,r);
    if(mid<r) seg_max(x<<1|1,l,r);
}
void change(ll x,ll ooo,ll val){
    if(tr[x].l==tr[x].r) {
        tr[x].val=max(tr[x].val,val);
        return ;
    }
    if(tr[x].f) down(x);
    ll mid=(tr[x].l+tr[x].r)>>1;
    if(ooo<=mid) change(x<<1,ooo,val);
    else change(x<<1|1,ooo,val);
    up(x);
}
void seg_change(ll x,ll l,ll r,ll val){
    if(l>r) return;
    if(tr[x].f) down(x);
    if(tr[x].l>=l&&tr[x].r<=r){
        tr[x].val+=val;
        tr[x].f+=val;
        return ;
    }
    ll mid=(tr[x].l+tr[x].r)>>1;
    if(mid>=l) seg_change(x<<1,l,r,val);
    if(mid<r) seg_change(x<<1|1,l,r,val);
    up(x);
}
int main(){
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
        scanf("%lld%lld%lld",&s[i].a,&s[i].b,&s[i].w),lsh[++cnt]=s[i].a,lsh[++cnt]=s[i].b;
    sort(lsh+1,lsh+cnt+1);
    len=unique(lsh+1,lsh+cnt+1)-lsh-1;
    for(ll i=1;i<=n;i++){
        s[i].a=lower_bound(lsh+1,lsh+len+1,s[i].a)-lsh;
        s[i].b=lower_bound(lsh+1,lsh+len+1,s[i].b)-lsh;
    }
    sort(s+1,s+n+1);
    built(1,1,len);
    for(ll i=1;i<=n;i++){
        if(s[i].a>s[i].b){
            maxn=0;
            seg_max(1,1,s[i].b);
            change(1,s[i].a,s[i].w+maxn);
        }
        else {
            seg_change(1,s[i].a,s[i].b,s[i].w);
            maxn=0;
            seg_max(1,1,s[i].a-1);
            change(1,s[i].a,s[i].w+maxn);
        }
    }
    maxn=0;
    seg_max(1,1,len);
    printf("%lld\n",maxn);
}
View Code

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!