题意:
一个正方形地图上给定N个点,从 (0,0) 开始走向 (1e9,1e9),地图中每个点都有一个权值,只有从 (x-1,y-1)到达 (x,y)这个点,(x,y)这个点的权值才能够获得。要求走到终点时所获得的权值最大。
思路:
将点的 y 值离散化到数组 a 上,再将所有点按照 x 进行排序,从第一列遍历到最后一列,对于第 i 列上的每一个点,求出 (1 , i-1) 列上 dp 的最大值,用树状数组进行记录。
更新dp[ i ]的同时对 ans 取最大值,最后ans的值就是答案。
代码:
#include <bits/stdc++.h>
using namespace std;
struct Node {
int x, y, v;
void input() {
scanf("%d%d%d", &x ,&y, &v);
}
}node[100010];
bool cmp(Node a, Node b) {
return a.x < b.x;
}
int a[100010];
int tot;
int c[100010]; //树状数组,c[i]表示【i-lowbit(i)+1,i】这个区间维护的值
int lowbit(int x) {
return x&(-x);
}
void update(int i, int val) {
while (i <= tot) {
c[i] = max(c[i], val);
i += lowbit(i);
}
}
int query(int i) { //求出【1,i】区间维护的内容,可以求sum,也可以求max/min
int res = 0;
while (i > 0) {
res = max(res, c[i]); //维护最大值
i -= lowbit(i);
}
return res;
}
int dp[100010];
int main() {
int T;
int n;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
//读入点
for (int i = 0; i < n; i++)
node[i].input();
//将y读入数组a,进行离散化
tot = 0;
for (int i = 0; i < n; i++) {
a[tot++] = node[i].y;
}
sort(a, a+tot);
//离散化后进行去重
tot = unique(a, a+tot) - a;
//排序后再将标号传回去
for (int i = 0; i < n; i++) {
node[i].y = lower_bound(a, a+tot, node[i].y) - a + 1;
}
//对x坐标排序
sort(node, node+n, cmp);
for (int i = 0; i < n; i++) dp[i] = node[i].v;
//c[i]是树状数组,c[i]表示【i-lowbit(i)+1,i】这个区间,长度为lowbit(i)
for (int i = 1; i <= tot; i++)c[i] = 0;
int pos = 0;
int ans = 0;
//从第一列开始往之后的列更新
//对于每个点求该点之前的最大值进行更新
for (int i = 0; i < n; i++) {
while (pos < i && node[pos].x < node[i].x) {
update(node[pos].y, dp[pos]);
pos++;
}
dp[i] = query(node[i].y - 1) + node[i].v;
ans = max(ans, dp[i]);
}
printf("%d\n",ans);
}
return 0;
}