https://blog.csdn.net/Izumi_Hanako/article/details/78276844

首先,DP的关键在于将状态转移方程

的限制条件简化到一个数据的大小排列。即

可以发现,每个物品相当于有两个值。j的两个值都小于i时就可以转移。
把其中的某一个权值排序,然后用树状数组(或者线段树)维护另一个权值就好了(这里需要离散化)。
每次转移都是前缀最大值进行转移。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

const int maxn = 1e5+5;
int t[maxn],p[maxn],v[maxn];
int w,n;
int uninum;
                              //树状数组是怎么解决二维的限制条件的呢?遍历顺序和数组下标(离散化)
                              //也就是第a次在b位置更新val[a]的值
class BIT{
    public:
        void update(int pos,int val){
            for(; pos<=n; pos+=(-pos)&pos){
                B[pos] = max(B[pos], val);
            }
        }
        int query(int pos){     //查询是直接查前缀的结果,即1~pos
            int res=0;
            for(; pos>=1; pos-=(-pos)&pos){
                res = max(res, B[pos]);
            }
            return res;
        }
        void init(){
            memset(B,0,sizeof(B));
        }
    private:
        int B[maxn];
}BI;

struct Data{
    int t,p,v;
    int a,b;
    bool operator < (const Data &A) const{
        return a<A.a;
    }
}s[maxn];

struct Unique_Data{
    int b,id;
    bool operator < (const Unique_Data & U) const{
        return b<U.b;
    }
}uni[maxn];

void Unique(){
    sort(uni+1, uni+1+n);
    uni[0].b = -2147483647;
    for(int i=1; i<=n; i++){
        if(uni[i].b != uni[i-1].b)
            uninum++;
        s[ uni[i].id ].b = uninum;
    }
}

void solve(){
    sort(s+1, s+1+n);
    BI.init();
    for(int i=1; i<=n; i++){
        BI.update(s[i].b, BI.query(s[i].b)+s[i].v);    //树状数组处理的是前缀,所以只需要更新1次就处理了一段区间
    }
    cout<<BI.query(uninum)<<endl;
}

int main(){
    ios::sync_with_stdio(false);
      cin.tie(0);
    cin>>w>>n;
    for(int i=1; i<=n; i++){
        cin>>s[i].t>>s[i].p>>s[i].v;
        s[i].a = 2*s[i].t+s[i].p;
        uni[i].b = 2*s[i].t-s[i].p;
        uni[i].id = i;
    }
    Unique();
    solve();
}
02-01 09:11