P3431 [POI2005]AUT-The Bus
题目描述:
若是这个
n
n
n 和
m
m
m 比较小的话就是经典的
d
p
dp
dp 了。但是这里值域比较大,没法像经典做法那么做。但是本质没有变,对于某个点
(
x
,
y
)
(x,y)
(x,y) 来说,实际上就是在
(
1
~
x
,
1
~
y
)
(1~x,1~y)
(1~x,1~y) 这个矩阵里面找到一个最大的
d
p
dp
dp 值,再加上自己的权值,就是这个点的答案了。那么我们可以先离散化,然后以
x
x
x 优先,
y
y
y 其后,以
y
y
y 为下标,维护一个区间最大值(实际上只要维护前缀最大值),这里感觉看代码会更好理解。。。这样的话在求
(
x
,
y
)
(x,y)
(x,y) 的
d
p
dp
dp 值的时,我们先在数据结构上询问
(
1
,
y
)
(1,y)
(1,y) 这个区间的
d
p
dp
dp 最大值,实际上是询问了前面所有纵坐标在
[
1
,
y
]
[1,y]
[1,y] 中的点的
d
p
dp
dp 值的最大值,然而我现在只遍历到了
x
x
x 行,也就是说求得的是
(
1
~
x
,
1
~
y
)
(1~x,1~y)
(1~x,1~y) 这个矩阵内所有点的最大值,即是我们想要的最大值,加上自己这个点的权值便是自己这个点的答案。对每个点的答案取
m
a
x
max
max 便是最终答案。这题的精髓就在于我们发现可以用排序后遍历的方式当作时间轴,将这个问题降为一维。
#include <bits/stdc++.h>
#define lson rt<<1
#define rson (rt<<1)|1
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
struct Point {
int x; int y; int v;
}p[N];
int n, m, k, t1[N], t2[N], tot1, tot2;
ll bit[N], ans;
bool cmpy(Point a, Point b) {
if (a.x ^ b.x) return a.x < b.x;
return a.y < b.y;
}
void add(int i, ll v) {
while(i <= tot2) {
bit[i] = max(bit[i], v);
i += i & (-i);
}
}
ll query(int i) {
ll mx = -1e18;
while(i) {
mx = max(mx, bit[i]);
i -= i & (-i);
}
return mx;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= k; ++i) {
scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].v);
t1[i] = p[i].x;
t2[i] = p[i].y;
}
sort(t1 + 1, t1 + 1 + k);
sort(t2 + 1, t2 + 1 + k);
tot1 = unique(t1 + 1, t1 + 1 + k) - t1 - 1;
tot2 = unique(t2 + 1, t2 + 1 + k) - t2 - 1;
for (int i = 1; i <= k; ++i) {
p[i].x = lower_bound(t1 + 1, t1 + 1 + tot1, p[i].x) - t1;
p[i].y = lower_bound(t2 + 1, t2 + 1 + tot2, p[i].y) - t2;
}
sort(p + 1, p + 1 + k, cmpy);
for (int i = 1; i <= k; ++i) {
ll cur = query(p[i].y) + p[i].v;
ans = max(ans, cur);
add(p[i].y, cur);
}
printf("%lld", ans);
}