hdu6447(树状数组+离散化优化dp)

YJJ's Salesman

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2161    Accepted Submission(s): 809

Problem Description

YJJ is a salesman who has traveled through western country. YJJ is always on journey. Either is he at the destination, or on the way to destination.
One day, he is going to travel from city A to southeastern city B. Let us assume that A is (0,0) on the rectangle map and B (109,109). YJJ is so busy so he never turn back or go twice the same way, he will only move to east, south or southeast, which means, if YJJ is at (x,y) now (0≤x≤109,0≤y≤109), he will only forward to (x+1,y), (x,y+1) or (x+1,y+1).
On the rectangle map from (0,0) to (109,109), there are several villages scattering on the map. Villagers will do business deals with salesmen from northwestern, but not northern or western. In mathematical language, this means when there is a village k on (xk,yk) (1≤xk≤109,1≤yk≤109), only the one who was from (xk−1,yk−1) to (xk,yk) will be able to earn vk dollars.(YJJ may get different number of dollars from different village.)
YJJ has no time to plan the path, can you help him to find maximum of dollars YJJ can get.

Input

The first line of the input contains an integer T (1≤T≤10),which is the number of test cases.

In each case, the first line of the input contains an integer N (1≤N≤105).The following N lines, the k-th line contains 3 integers, xk,yk,vk (0≤vk≤103), which indicate that there is a village on (xk,yk) and he can get vk dollars in that village.
The positions of each village is distinct.

Output

The maximum of dollars YJJ can get.

Sample Input

1

3

1 1 1

1 2 2

3 3 1

Sample Output

3

Source

2018中国大学生程序设计竞赛 - 网络选拔赛

解析:首先,我们可以想到dp[i][j]=max(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]+val[i][j]); 因为给出的图很大,(0,0)~(1e9,1e9)所以我们要对x轴离散化优化。x按照从大到小,y从小到大。然后从下往上,从左往右更新每一个点的val。维护dp[i],则dp[j]=max(dp[j],dp[i]+val[i][j])0<i<j-1,dp[i]表示在离散化后的0到j-i行中,最大价值的那个值。然后可以转换为树状数组区间找最值问题。

粗略的dp[j]=max(dp[j],getsum(0~i)+val)

但是为什么要这么排序呢?x按照从大到小,y从小到大。因为我们是从(0,0)点开始走的,每一列的其中一个位置,都要从它的上一列和上一行取得最大值。

(1,1)(1,2)(1,3)

(2,1)(2,2)(2,3)

(3,1)(3,2)(3,3)

就像我要取(3,3)的max值,我们要从(除了(3,3)点)中找一个最大值。又因为我们是从第一列开始,所以我们就要每次从x最大那一行开始更新,比如排序后先更新(3,1)然后我们要是最后是到(3,2)。我们还要更新(2,1),然后最后到(3,2)我们就要取1~3行的最值不包括第3列的行,因为我们还没到3列。具体看代码了解,有点说不清楚

#include<bits/stdc++.h>
using namespace std;

#define e exp(1)
#define pi acos(-1)
#define mod 1000000007
#define inf 0x3f3f3f3f
#define ll long long
#define ull unsigned long long
#define mem(a,b) memset(a,b,sizeof(a))
int gcd(int a,int b){return b?gcd(b,a%b):a;}

const int maxn=1e5+10;
int n,c[maxn],x[maxn];
struct node{
	int x,y,w;
	bool operator < (const node &r)const{
		if(y==r.y)return x>r.x;
		return y<r.y;
	}
}a[maxn];
int lowbit(int x)
{
	return x&(-x);
}
void add(int i,int val)
{
	while(i<=n)
	{
		c[i]=max(c[i],val);
		i+=lowbit(i);
	}
}
int getsum(int i)
{
	int ans=0;
	while(i>0)
	{
		ans=max(ans,c[i]);
		i-=lowbit(i);
	}
	return ans;
}

int main()
{
	int T;scanf("%d",&T);
	while(T--)
	{
		mem(c,0);
		scanf("%d",&n);
		for(int i=1; i<=n; i++)
		{
			scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
			x[i]=a[i].x;
		}
		sort(x+1,x+n+1);
		sort(a+1,a+n+1);
		int ans=0;
		for(int i=1; i<=n; i++)
		{
			int cnt=lower_bound(x+1,x+n+1,a[i].x)-x;//离散化 
			int num=a[i].w+getsum(cnt-1);//更新0~cnt-1行 的最值 
			ans=max(ans,num);
			add(cnt,num);//在cnt行插入num。 
		}
		printf("%d\n",ans);
	}
	return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值