P3431 [POI2005]AUT-The Bus【树状数组+离散化】【二维偏序】

本文探讨了一个在n*m范围内寻找经历路径上的最大点权值的问题,通过二维偏序思想,采用树状数组进行区间修改和查询,实现对点的离散化和排序,最终求得最大前缀和。

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

题意:

n*m的范围内有k个点
1≤n≤109,1≤m≤1091\leq n \leq 10^9 ,1\leq m \leq 10^91n109,1m109
你从(0, 0)出发到(n,m) 每次你只能往上或往右移动,求经历的路径最大点权值

思路:

也就是说我们要让点经历的xi≤xi+1,yi≤yi+1x_i \leq x_{i+1},y_i \leq y_{i+1}xixi+1,yiyi+1
也就是二维偏序,求最大前缀和
先对y坐标排序,离散化
树状数组,区间修改 改成 维护最大前缀和 区间查询 改成查询最大前缀和
然后再对点根据x坐标排序

AC_code:

/*
Algorithm:
Author: anthony1314
Creat Time:
Time Complexity:
*/
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+5;
int bit[MAXN];
int cnt = 0;
struct node {
	int x, y, val;
} p[MAXN];
bool cmp1(node aa, node bb) {
	return aa.y < bb.y;
}
bool cmp2(node aa, node bb) {
	if(aa.x == bb.x) {
		return aa.y < bb.y;
	}
	return aa.x < bb.x;
}
int lowbit(int x) {
	return x&(-x);
}
void add(int i,int x) {
	while(i<=cnt) {
//		bit[i]+=x;
		bit[i] = max(bit[i], x);
		i+=lowbit(i);
	}
}
int sum(int i) {
	int s=0;
	while(i>0) {
//		s+=bit[i];
		s = max(s, bit[i]);
		i-=lowbit(i);
	}
	return s;
}

int main() {
	int n, m, k;
	cin>>n>>m>>k;
	for(int i = 1; i <= k; i++) {
		scanf("%d %d %d", &p[i].x, &p[i].y, &p[i].val);
	}
	//对y排序 离散化
	sort(p+1, p+1+k, cmp1);
	int now = p[1].y;
	p[1].y = ++cnt;
	for(int i = 2; i <= k; i++) {
		if(p[i].y != now) {
			now = p[i].y;
			p[i].y = ++cnt;
		} else {
			p[i].y = cnt;
		}
	}
	// 对x排序  再对y排序   左下优先
	sort(p+1, p+1+k, cmp2);
	int res;
	int ans = 0;//当前的最大前缀和
	for(int i = 1; i <= k; i++) {
		res = sum(p[i].y)+p[i].val;
		//cout<<res<<endl;
		add(p[i].y, res);
		ans = max(res, ans);
	}
	cout<<ans<<endl;

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值