题意:
每个人有3个属性a,b,c。
求选择一些人,使得任意两个人,要么a,b严格大于另一个人,要么完全相同。
求最大的c值和。
思路:
有两维状态的限制,类似于偏序。
定义
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]代表考虑了前
i
i
i个人,b的值为
j
j
j时的最大
c
c
c值和。
把a,b值完全相同的人先合并。
我们一维一维的考虑,先按照第一维度a排序从小到大,第二维度按照b排序从大到小,则从后往前遍历就保证了已经更新过的人 b b b大于自己(或者b等于自己,但是他的c值小于自己,所以不会影响到自己)。
那么转移就是
d
p
[
i
]
[
a
[
i
]
.
b
]
]
=
m
a
x
(
d
p
[
i
+
1
]
[
j
]
)
,
j
>
a
[
i
]
.
b
dp[i][a[i].b]]=max(dp[i+1][j]),j>a[i].b
dp[i][a[i].b]]=max(dp[i+1][j]),j>a[i].b,
这个过程可以用线段树维护。
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 7;
struct Node {
int x,y;
ll z;
bool operator < (const Node&rhs) const {
if(x != rhs.x) return x < rhs.x;
return y > rhs.y;
}
}a[maxn];
vector<int>vec;
struct Tree {
int l,r;
ll mx,lazy;
}t[maxn << 2];
void pushdown(int i) {
if(t[i].lazy) {
t[i * 2].lazy = max(t[i * 2].lazy,t[i].lazy);
t[i * 2].mx = max(t[i * 2].mx,t[i].lazy);
t[i * 2 + 1].lazy = max(t[i * 2 + 1].lazy,t[i].lazy);
t[i * 2 + 1].mx = max(t[i * 2 + 1].mx,t[i].lazy);
}
}
void pushup(int i) {
t[i].mx = max(t[i * 2].mx,t[i * 2 + 1].mx);
}
void build(int i,int l,int r) {
t[i].l = l;t[i].r = r;
if(l == r) {
return;
}
int m = (l + r) >> 1;
build(i * 2,l,m);
build(i * 2 + 1,m + 1,r);
pushup(i);
}
ll query(int i,int x,int y) {
if(x > y) return 0;
if(x <= t[i].l && t[i].r <= y) {
return t[i].mx;
}
int m = (t[i].l + t[i].r) >> 1;
ll res = 0;
pushdown(i);
if(x <= m) {
res = max(res,query(i * 2,x,y));
}
if(y > m) {
res = max(res,query(i * 2 + 1,x,y));
}
return res;
}
void update(int i,int x,int y,ll v) {
if(x > y) return ;
if(x <= t[i].l && t[i].r <= y) {
t[i].lazy = max(t[i].lazy,v);
t[i].mx = max(t[i].mx,v);
return;
}
pushdown(i);
int m = (t[i].l + t[i].r) >> 1;
if(x <= m) update(i * 2,x,y,v);
if(y > m) update(i * 2 + 1,x,y,v);
pushup(i);
}
int main() {
int n;scanf("%d",&n);
for(int i = 1;i <= n;i++) {
scanf("%d%d%lld",&a[i].x,&a[i].y,&a[i].z);
vec.push_back(a[i].y);
}
sort(a + 1,a + 1 + n);
sort(vec.begin(),vec.end());
vec.erase(unique(vec.begin(),vec.end()),vec.end());
int cnt = 0;
for(int i = 1;i <= n;i++) {
if(cnt && a[cnt].x == a[i].x && a[cnt].y == a[i].y) {
a[cnt].z += a[i].z;
} else {
a[++cnt] = a[i];
}
}
n = cnt;
int len = vec.size();
build(1,1,len);
ll ans = 0,pre = 0;
for(int i = n;i >= 1;i--) {
int pos = lower_bound(vec.begin(),vec.end(),a[i].y) - vec.begin() + 1;
ll num = query(1,pos + 1,len) + a[i].z;
ans = max(ans,num);
update(1,1,pos,num);
}
printf("%lld\n",ans);
return 0;
}