P3431 [POI2005]AUT-The Bus-----DP + 树状数组 + 二维坐标离散化

这篇博客讲解了如何在P3431 POI2005竞赛题目中,利用二维坐标离散化和树状数组的数据结构进行动态规划,解决公交线路问题。重点介绍了如何使用dp数组与树状数组的updata和ask操作来维护区间最大值。
摘要由CSDN通过智能技术生成

题目描述:P3431 [POI2005]AUT-The Bus
该题二维坐标分布广,且点稀疏,所以对点坐标进行离散化,二维坐标离散化(蒟蒻)
利用树状数组的动态维护区间的特性,进行动态规划
DP+树状数组 核心代码:

for(int i = 1; i <= k; i++){
		// 能走到f[i].y 的最大值 与 f[i].k的值和作为 dp[ i ]的值
		dp[i] = ask( f[i].y) + f[i].k;

		// 由于 f[ i ]点的加入,更新右边的dp[ ]
		updata(f[i].y, dp[i]);
}

下图与核心代码搭配食用
dp[ ] 就相当于 t[ ],通过树状数组维护

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n, m, k, ans;
int x[maxn], y[maxn], val[maxn];
int nx[maxn*2], ny[maxn*2], tot1 = 1, tot2 = 1;
int t[maxn*2], dp[maxn*2];
struct node {
	int x, y, k;
}f[maxn], a[maxn];
bool cmp(const node &aa, const node &bb){
		return (aa.x==bb.x?aa.y<bb.y:aa.x<bb.x);
}
void updata(int x, int k){
	for( ; x <= tot2; x += x&-x){
		t[x] = max(t[x], k);
	}
}
int ask(int x){
	int maxx = 0;
	for( ; x; x -= x&-x){
		maxx = max(t[x], maxx);
	}
	return maxx;
}
int main(){
	cin >> n >> m >> k;
	for(int i = 1; i <= k; i++){
		cin >> x[i] >> y[i] >> a[i].k;
		a[i].x = x[i], a[i].y = y[i];
	}
	a[k + 1].x = n, a[k + 1].y = m, a[k + 1].k = 0;
	// 离散化
	x[0] = 1, y[0] = 1;
	x[k + 1] = n, y[k + 1] = m;

	// 排序
	sort(x, x + k + 2);
	sort(y, y + k + 2);
	// 去重 和 不重复数组长度
	int len1 = unique(x, x + k + 2) - x;
	int len2 = unique(y, y + k + 2) - y;

	// 离散化 x 轴
	for(int i = 0; i < len1; i++){
		if(i && x[i] != x[i - 1] + 1)
			nx[tot1++] = x[i] - 1, nx[tot1++] = x[i];
		else
			nx[tot1++] = x[i];
	}
	// 离散化 y 轴
	for(int i = 0; i < len2; i++){
		if(i && y[i] != y[i - 1] + 1)
			ny[tot2++] = y[i] - 1, ny[tot2++] = y[i];
		else
			ny[tot2++] = y[i];
	}
	// 得到离散化后的坐标
	for(int i = 1; i <= k + 1; i++){
		int newx = lower_bound(nx, nx + tot1 + 1, a[i].x) - nx;
		int newy = lower_bound(ny, ny + tot2 + 1, a[i].y) - ny;
		f[i].x = newx, f[i].y = newy, f[i].k = a[i].k;
	}
	
	// 以 x 轴为第一关键字,y 轴为第二关键字  进行排列
	sort(f + 1, f + k + 1, cmp);

	// dp + 树状数组
	for(int i = 1; i <= k; i++){
		dp[i] = ask( f[i].y) + f[i].k;
		updata(f[i].y, dp[i]);
	}
	for(int i = 1; i <= k; i++)	ans = max(ans, dp[i]);
	cout << ans << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值