Description
Byte City 的街道形成了一個標准的棋盤網絡 – 他們要么是北南走向要么就是西東走向. 北南走向的路口從 1 到 n編號, 西東走向的路從1 到 m編號. 每個路口用兩個數(i, j) 表示(1 <= i <= n, 1 <= j <= m). Byte City里有一條公交線, 在某一些路口設置了公交站點. 公交車從 (1, 1) 發車, 在(n, m)結束.公交車只能往北或往東走. 現在有一些乘客在某些站點等車. 公交車司機希望在路線中能接到盡量多的乘客.幫他想想怎么才能接到最多的乘客.
Input
第一行為三個整數\(n,m,k\)
下面\(k\)行給出\(k\)個三元組\((x,y,k)\),表示\((x,y)\)位置有\(k\)個乘客.
Output
一個整數,表示最多能接到的乘客數.
很容易看出,我們的路線是向右上方運動的。
不知道為什么想到了二維偏序.
我們首先對\(y\)排序,離散化.(\(n,m \leq 10^9\))
然后很容易發現,我們的狀態轉移為
\[f[i]=f[j]+val[i] \ (i>j &&\ y[i]>y[j]) \]
這時候維護當前位置之前的最大值即可.
如何維護呢?用樹狀數組!
為什么可以用樹狀數組?
樹狀數組維護的是一個前綴和,這題不要求我們求區間最大值,而是求前綴最大值,因此可以用.
然后再對橫坐標\(x\)排序.
每次操作即可.
代碼
#include<cstdio>
#include<cctype>
#include<iostream>
#include<algorithm>
#define R register
using namespace std;
inline void in(int &x)
{
int f=1;x=0;char s=getchar();
while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
while(isdigit(s)){x=x*10+s-'0';s=getchar();}
x*=f;
}
int n,m,q,tr[100005];
struct cod{int x,y,val;}p[100005];
int now,ans,cnt;
inline bool cpp(const cod&a,const cod&b)
{
return a.y<b.y;
}
inline bool ccp(const cod&a,const cod&b)
{
if(a.x==b.x)return a.y<b.y;
return a.x<b.x;
}
#define lowbit(x) x&-x
inline void add(int x,int y){for(;x<=cnt;x+=lowbit(x))tr[x]=max(tr[x],y);}
inline int query(int x){int res=0;for(;x;x-=lowbit(x))res=max(res,tr[x]);return res;}
int main()
{
in(n),in(m),in(q);
for(R int i=1;i<=q;i++)
in(p[i].x),in(p[i].y),in(p[i].val);
sort(p+1,p+q+1,cpp);
now=p[1].y,p[1].y=++cnt;
for(R int i=2;i<=q;i++)
{
if(p[i].y!=now)
now=p[i].y,p[i].y=++cnt;
else p[i].y=cnt;
}
sort(p+1,p+q+1,ccp);
for(R int i=1,now;i<=q;i++)
{
now=query(p[i].y)+p[i].val;
ans=max(ans,now);
add(p[i].y,now);
}
printf("%d",ans);
}