HDU 6447 YJJ's Salesman(线段树+DP)

YJJ's Salesman

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


题目链接

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

 

题意:

你从(0,0)开始走到(1e9,1e9),当你在(x,y)时,只能走到(x,y+1),(x+1,y),(x+1,y+1)

然后有n个点是具有权值的,假定该点是(x,y),你要获得他的权值,必须从(x-1,y-1)走一步到(x,y)

问你整个过程中,你能获得的最大权值是多少

 

解析:

这里点很大,可以达到1e9,但n只有1e5,所以可以把他们离散化,就可以存储了。

dp[x]表示到达第x行的最大值

然后,按列遍历,按照行从大到小遍历一列上的点,x=point[i].tl(离散化后的行数),dp[x]=max(dp[x],dp[j]+point[i].w)  (j=1....x-1)

这里从大到小遍历一列的元素,是因为dp[j]都是上一列的状态。这样你就只要遍历一个更新一个就可以了,不然你还要再用一个

数组记录该列的dp(区分上一个列的状态),然后一列结束后,再一一更新

那么这个dp,其实可以用线段树维护最大值,每一次如果dp[x]被更新,对应也要更新线段树上的点

复杂度为O(nlogn)

#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
#define Max(a,b) a>=b?a:b
#define lch (root<<1)
#define rch ((root<<1)|1)
using namespace std;

const int MAXN = 1e5+10;

int n;
typedef struct node
{
	int l,r;
	int w;
	int tl;
}node;
node point[MAXN];

map<int,int> mp;

bool cmp(node a,node b)
{
	if(a.l==b.l) return a.r>b.r;
	return a.l<b.l;
}

bool cmp1(node a,node b)
{
	return a.r<b.r;
}

int Btree[MAXN*4];
int dp[MAXN];



void build(int l,int r,int root)  //l,r表示他们在stu中的下标,root表示他们在线段树中的坐标
{
	if(l>r)return;
	if(l==r)
	{
		Btree[root]=0;
		dp[l]=0;
		return;
	}

	int mid=(l+r)/2;
	
	build(l,mid,root*2);
	build(mid+1,r,root*2+1);

	Btree[root]=Max(Btree[root*2],Btree[root*2+1]);
}



void updateone(int root,int l,int r,int index,int val)
{
	if(l>r)return;
	if(l==r)
	{
		if(l==index)
			Btree[root]=val;
		return;
	}

	int mid=(l+r)/2;
	if(index<=mid)
		updateone(root*2,l,mid,index,val);
	else 
		updateone(root*2+1,mid+1,r,index,val);

	Btree[root]=Max(Btree[2*root],Btree[2*root+1]);
}

int query(int root,int s1,int e1,int s2,int e2)
{
	if(e1<s2||s1>e2)
		return -1;
	if(s1>e1)return -1;
	if(s1>=s2&&e1<=e2)
	{
		return Btree[root];
	}

	//pushDown(root);
	int mid=(s1+e1)/2;
	int la,ra;
	la=ra=-1;
	if(s2<=mid) la=query(lch,s1,mid,s2,e2);
	if(e2>mid) ra=query(rch,mid+1,e1,s2,e2);
	return Max(la,ra);
	
}




int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		//mp.clear();
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d%d%d",&point[i].l,&point[i].r,&point[i].w);
		}
		sort(point+1,point+1+n,cmp1);
		int cnt=1;
		//mp[point[1].r]=cnt;
		point[1].tl=cnt;
		for(int i=2;i<=n;i++)
		{
			if(point[i].r!=point[i-1].r)
			{
				point[i].tl=++cnt;
			}
			else
			{
				point[i].tl=cnt;
			}
		}
		sort(point+1,point+1+n,cmp);
		build(1,cnt,1);
	    int tmp;
		int u;
		for(int i=1;i<=n;i++)
		{
			u=point[i].tl;
			tmp=u==1?0:query(1,1,cnt,1,u-1);
			/*if(u==1) tmp=0;
			else tmp=query(1,1,cnt,1,u-1);*/
			if(tmp+point[i].w>dp[u])
			{
				dp[u]=tmp+point[i].w;
				updateone(1,1,cnt,u,dp[u]);
			}
		}
		printf("%d\n",query(1,1,cnt,1,cnt));
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值