HDU 6447 YJJ's Salesman(dp+BIT)

本文介绍了一种在二维平面上寻找从特定起点到终点路径的算法,旨在通过经过一系列点获得最大收益。算法将点按横坐标离散化,并使用动态规划和二进制索引树来高效计算最大收益,适用于处理大量点的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

给出二维平面上的nnn个不同的点(xi,yi)(x_i,y_i)(xi,yi),现在要从(0,0)(0,0)(0,0)走到(109,109)(10^9,10^9)(109,109),每次只能从(x,y)(x,y)(x,y)走到(x,y+1),(x+1,y),(x+1,y+1)(x,y+1),(x+1,y),(x+1,y+1)(x,y+1),(x+1,y),(x+1,y+1)中的一点,且如果是从(xk−1,yk−1)(x_k-1,y_k-1)(xk1,yk1)走到(xk,yk)(x_k,y_k)(xk,yk)的话,会收益vkv_kvk,问从(0,0)(0,0)(0,0)走到(109,109)(10^9,10^9)(109,109)的最大收益

Input

第一行一整数TTT表示用例组数,每组用例首先输入一整数nnn表示点数,之后nnn行每行输入三个整数xk,yk,vkx_k,y_k,v_kxk,yk,vk表示第kkk个点的坐标和价值

(1≤T≤10,1≤n≤105,0≤xk,yk≤109)(1\le T\le 10,1\le n\le 10^5,0\le x_k,y_k\le 10^9)(1T10,1n105,0xk,yk109)

Output

输出最大收益

Sample Input

1
3
1 1 1
1 2 2
3 3 1

Sample Output

3

Solution

把所有点按横坐标离散化为mmm列,以dp[i]dp[i]dp[i]表示从起点到第iii列的最大收益,把所有点按纵坐标排序,按横坐标离散化后的值转移即可,即对于当前点(x,y,v)(x,y,v)(x,y,v)(不妨认为xxx是离散化后的横坐标),有转移
dp[x]=max(dp[i],1≤i&lt;x)+v dp[x]=max(dp[i],1\le i&lt;x)+v dp[x]=max(dp[i],1i<x)+v
BITBITBIT维护一下dpdpdp数组的前缀和最大值即可,时间复杂度O(nlogn)O(nlogn)O(nlogn)

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=100005;
struct BIT 
{
	#define lowbit(x) (x&(-x))
	int b[maxn],n;
	void init(int _n)
	{
		n=_n;
		for(int i=1;i<=n;i++)b[i]=0;
	}
	void update(int x,int v)
	{
		while(x<=n)
		{
			b[x]=max(b[x],v);
			x+=lowbit(x);
		}
	}
	int query(int x)
	{
		int ans=0;
		while(x)
		{
			ans=max(b[x],ans);
			x-=lowbit(x);
		}
		return ans;
	}
}bit;
struct node
{
	int x,y,v;
	bool operator<(const node &b)const
	{
		if(y!=b.y)return y<b.y;
		return x>b.x;
	}
}a[maxn];
int T,n,h[maxn],dp[maxn];
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v);
		a[n+1].x=a[n+1].y=a[n+1].v=0;
		a[n+2].x=a[n+2].y=1e9,a[n+2].v=0;
		n+=2;
		sort(a+1,a+n+1);
		for(int i=1;i<=n;i++)h[i-1]=a[i].x;
		sort(h,h+n);
		int m=unique(h,h+n)-h;
		for(int i=1;i<=n;i++)a[i].x=lower_bound(h,h+m,a[i].x)-h+1;
		bit.init(m);
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=n;i++)
		{
			int id=a[i].x;
			dp[id]=max(dp[id],bit.query(id-1)+a[i].v);
			bit.update(id,dp[id]);
		}
		int ans=0;
		for(int i=1;i<=m;i++)ans=max(ans,dp[i]);
		printf("%d\n",ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值