题意:
一个人要从(0,0)的村庄走到(1e9,1e9)的村庄,有些村庄有 w 值。他只能斜着走才能获得那些值,问你他最多可以获得多少值。
题解:
如题我们可以得到 dp 公式 :dp[i][j] = max(dp[i-1][j-1]+w, dp[i-1][j], dp[i][j-1], w)。
但是我们直接离散化后去跑整个图是不行的,因为图太大了。其实我们可以发现 dp[i][j] = max(dp[i-1][j-1]+w, max(dp[0][j]......dp[i-1][j]), max(dp[i][0]......dp[i][j-1]), w),这样我们如果可以快速找到第 i 行 0 ... j-1中最大值,去更新就会快很多不用每个都更新,用线段树去查询最大值。我们还可以优化二维数组,我们可以像一维背包一样把 dp[i][j] 看做 tree[j],i 从小往大更新即可。
更新公式就变为 :tree[j] = max(tree[j],tree[0]...tree[j-1]+w),tree[j]在维护的过程中就是第 j 列的最大值不用去找。
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <stack>
#include <cmath>
#include <deque>
#include <queue>
#include <list>
#include <set>
#include <map>
#define mem(a, b) memset(a, b, sizeof(a))
#define inf 0x7ffffff
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
int tree[maxn << 2], disperse_x[maxn], disperse_y[maxn];
struct node{
int x, y, w;
}point[maxn];
int cmp(node a, node b){
if(a.x == b.x){
return a.y > b.y;
}
return a.x < b.x;
}
void build(int root, int l, int r){
if(l == r){
tree[root] = 0;
return;
}
int mid = (l + r) >> 1;
build(root << 1, l, mid);
build(root << 1 | 1, mid+1, r);
tree[root] = max(tree[root << 1], tree[root << 1 | 1]);
}
int query(int root, int l, int r, int ql, int qr){
if(l == ql && r == qr){
return tree[root];
}
int mid = (l + r) >> 1;
if(mid >= qr){
return query(root << 1, l, mid, ql, qr);
}
else if(mid < ql){
query(root << 1 | 1, mid+1, r, ql, qr);
}
else{
return max(query(root << 1, l, mid, ql, mid), query(root << 1 | 1, mid+1, r, mid+1, qr));
}
}
void update(int root, int id, int num, int l, int r){
if(l == r && l == id){
tree[root] = max(tree[root], num);
return;
}
int mid = (l + r) >> 1;
if(mid >= id){
update(root << 1, id, num, l, mid);
}
else{
update(root << 1 | 1, id, num, mid+1, r);
}
tree[root] = max(tree[root << 1], tree[root << 1 | 1]);
}
int main(){
int t;
scanf("%d", &t);
while(t--){
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++){
scanf("%d %d %d", &point[i].x, &point[i].y, &point[i].w);
disperse_x[i] = point[i].x;
disperse_y[i] = point[i].y;
}
sort(disperse_x, disperse_x+n);
sort(disperse_y, disperse_y+n);
int len1 = unique(disperse_x, disperse_x+n) - disperse_x;
int len2 = unique(disperse_y, disperse_y+n) - disperse_y;
for(int i = 0; i < n; i++){
point[i].x = lower_bound(disperse_x, disperse_x+len1, point[i].x) - disperse_x;
point[i].y = lower_bound(disperse_y, disperse_y+len2, point[i].y) - disperse_y;
}
sort(point, point+n, cmp);
build(1, 0, n);
int ans = 0;
for(int i = 0; i < n; i++){
int maxx = point[i].y == 0 ? point[i].w : query(1, 0, n, 0, point[i].y-1) + point[i].w;
update(1, point[i].y, maxx, 0, n);
ans = max(ans, maxx);
}
printf("%d\n", ans);
}
}