https://vjudge.net/contest/261263#problem/B(题目链接)
因为一秒可以走1或2步或不走。
我们可以看成半秒走1步或不走。
dp[i]表示接到第i块饼时最大的分数值
现在有两块饼它们下落的时间为ti,tj,位置为pi,pj;
假设ti > tj;
只有ti - tj >= |pi - pj| 时dp[j]可以转移到dp[i];
当pi > pj 时 ti -tj > pi - pj
ti - pi > tj - pj;
当pi < pj 时 ti -tj > pj - pi
ti + pi > tj + pj;
当pi > pj , ti -tj > pi - pj时 pj - pi < 0 , ti - tj > pj - pi;
当pi < pj , ti -tj > pj - pi时 pi - pj<0, ti -tj > pi - pj ;
所以dp[j]可以转移到dp[i]的条件是
ti + pi > tj + pj;并且ti - pi > tj - pj;
这是个二维偏序问题
我们把v1 看成 ti + pi, 把v2看成ti - pi
把v1看成第一维从小到大排序,v2 看成第二维用数据结构维护
先把v2离散化
在把所有饼按v1从小到大排序,再在以离散化后的v2为下标,dp为值的一棵值域线段树(我写的树状数组)上找能更新到这个点的最大的dp值。
树状数组维护区间最大值,支持修改和查询操作
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int w, n, sval[100005], ans, f[100005], dp[100005];
struct node
{
int v1, v2, val;
};
node q[100005];
bool cmp(const node a,const node b)
{
return a.v1 < b.v1;
}
int qurey(int a)
{
int rt = 0;
for(int i = a; i; i -= i &(-i))
{
rt = max(rt,f[i]);
}
return rt;
}
void modify(int a,int b)
{
for(int i = a; i <= n; i += i&(-i))
{
f[i] = max(f[i],b);
}
}
int main()
{
cin >> w >> n;
for(int i = 1; i <= n; i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
q[i].v1 = a * 2 + b;
q[i].v2 = a * 2 - b;
sval[i] = q[i].v2;
q[i].val = c;
}
sort(sval+1,sval+1+n);
int m = unique(sval+1,sval+1+n) - sval;
for(int i = 1; i <= n; i++)
{
q[i].v2 = lower_bound(sval+1,sval+1+m,q[i].v2) - sval;
}
sort(q+1,q+1+n,cmp);
for(int i = 1; i <= n; i++)
{
int ha = qurey(q[i].v2);
dp[i] = ha + q[i].val;
modify(q[i].v2,dp[i]);
}
for(int i = 1; i <= n; i++)
ans = max(dp[i],ans);
cout << ans << endl;
return 0;
}