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

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);
}

猜你喜欢

转载自www.cnblogs.com/-guz/p/9832354.html