Aut- The Bus

本文介绍了一道关于公交线路优化的问题,旨在求解从(1,1)到(n,m)能接到最多乘客的策略。通过离散化和使用树状数组,可以在大数据规模下有效地计算最大乘客数。给出了样例输入和输出,并提供了关键的优化思路及代码实现。" 89605439,7758931,C++ Primer 5th:深入解析模板与泛型编程,"['C++模板与泛型', '函数指针', '模板']

题目描述:

Byte City 的街道形成了一个标准的棋盘网络 – 他们要么是北南走向要么就是西东走向. 北南走向的路口从 1 到 n编号, 西东走向的路从1 到 m编号. 每个路口用两个数(i, j) 表示(1 <= i <= n, 1 <= j <= m). Byte City里有一条公交线, 在某一些路口设置了公交站点. 公交车从 (1, 1) 发车, 在(n, m)结束.公交车只能往北或往东走. 现在有一些乘客在某些站点等车. 公交车司机希望在路线中能接到尽量多的乘客.帮他想想怎么才能接到最多的乘客.

输入

第一行三个数n, m 和 k – 表示北南走向的路的个数以及西东走向的路和乘客等车的站点的个数. ( 1 <= n <= 10^9, 1 <= m <= 10^9, 1 <= k <= 10^5). 接下来k 行每行描述一个公交站的信息.第 i + 1 行三个正整数 xi, yi 和 pi, 1 <= xi <= n, 1 <= yi <= m, 1 <= pi <= 10^6. 表示在(xi, yi) 有 pi 个乘客在等车. 每个路口在数据中最多出现一次,乘客总数不会超过1 000 000 000.

输出

一个数表示最多能接到的乘客数量.

样例输入

8 7 11

4 3 4

6 2 4

2 3 2

5 6 1

2 5 2

1 5 5

2 1 1

3 1 1

7 7 1

7 4 2

8 6 2

样例输出

11

首先,O(nm)的dp很明显的吧,

f[i][j]表示从(1,1)走到(i,j)的max。

但是

数据范围: ( 1 <= n <= 10^9, 1 <= m <= 10^9, 1 <= k <= 10^5).

我们可以先离散化一下

然后

(重点来了)
设f[i]表示走到点i的最大值
将数组a以横坐标作为第一关键字,纵坐标作为第二关键字排序后
f[i]=max(f[j])+a[i].s(其间a[j].y<=a[i].y)
亲爱的童鞋们,看到这里是不是想到了什么优化?

没错,树状数组!

代码:

#include<bits/stdc++.h>
using namespace std;
map<int,int>t1,t2;
struct node{
    int x,y,s;
}a[500005];
int n,m,k,ans,x[500005],y[500005],c[500005],f[500005],tot1,tot2;
bool cmp(node t1,node t2){
	if(t1.x==t2.x)
		return t1.y<t2.y;
	return t1.x<t2.x;
} 
int lowbit(int x){
	return x&(-x);
}
void add(int x,int val){
    for(int i=x;i<=k;i+=lowbit(i))
		c[i]=max(c[i],val);
}
int sum(int x){
    int s=0;
    for(int i=x;i;i-=lowbit(i))
		s=max(s,c[i]);
    return s;
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=k;i++){
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].s);
        x[i]=a[i].x;
        y[i]=a[i].y;
    }
    x[0]=y[0]=1;
    sort(x,x+k+1);
    sort(y,y+k+1);
    t1[x[0]]=++tot1;
    t2[y[0]]=++tot2;
    for(int i=1;i<=k;i++){
        if(x[i]!=x[i-1])t1[x[i]]=++tot1;
        if(y[i]!=y[i-1])t2[y[i]]=++tot2;
    }
    for(int i=1;i<=k;i++)
		a[i].x=t1[a[i].x],a[i].y=t2[a[i].y];
    sort(a+1,a+k+1,cmp);
    for(int i=1;i<=k;i++){      
        f[i]=sum(a[i].y)+a[i].s;    
        add(a[i].y,f[i]);    
    }   
    for(int i=1;i<=k;i++)
		ans=max(ans,f[i]);
    printf("%d",ans);
    return 0;
}

AC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值