免费的馅饼(二维偏序)(树状数组版)

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
#include
#include
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;
} 

 

你可能感兴趣的:(noip训练,二维偏序,树状数组)