• [BZOJ1537][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 – 表示北南走向的路的个数以及西东走向的路和乘客等车的站点的个数. ( 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.

    Output

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

    Sample Input

    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

    Sample Output

    11


    显然的DP,设$f[i]$表示最后一个接了第$i$个车站的最多接的人数。

    然后$f[i] = max(f[j]) + p[i]$,$j$满足$x[j] leq x[i]$ and $y[j] leq y[i]$.

    于是我们可以把坐标按$x$轴从小到大排序,$x$相同按$j$从小到大排序,因为我们在更新$y$更大的时候的答案的时候可能从$y$更小的转移过来。

    我们已经保证了所有的可能转移过来的$j$的$x[j]$是小于等于$x[i]$的, 我们只要保证$y[j] leq y[i]$就行了。

    这样我们可以用树状数组维护纵坐标小于等于$y[i]$的最大值。

    对了坐标值的范围太大需要把纵坐标离散化。


    #include <iostream>
    #include <cstdio> 
    #include <algorithm>
    #include <cstring>
    #include <queue>
    using namespace std;
    #define reg register
    inline char gc() {
        static const int bs = 1 << 22;
        static unsigned char buf[bs], *st, *ed;
        if (st == ed) ed = buf + fread(st = buf, 1, bs, stdin);
        return st == ed ? EOF : *st++;
    }
    #define gc getchar
    inline int read() {
        int res=0;char ch=gc();bool fu=0;
        while(!isdigit(ch))fu|=(ch=='-'), ch=gc();
        while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48), ch=gc();
        return fu?-res:res;
    }
    #define N 1000005
    int n, m, K;
    int ans;
    struct date {
        int x, y, p;
        bool operator < (const date a) const {
            if (x == a.x) return y < a.y;
            return x < a.x;
        }
    }da[N];
    int f[N];
    int tr[N];
    int cpy[N], u;
    inline void change(int x, int y) {
        while(x <= u) {
            tr[x] = max(tr[x], y);
            x += x & -x;
        }
    }
    inline int query(int x) {
        int res = 0;
        while(x) {
            res = max(res, tr[x]);
            x -= x & -x;
        }
        return res;
    }
    
    int main()
    {
        n = read(), m = read(), K = read();
        for (reg int i = 1, t ; i <= K ; i ++) da[i] = (date){read(), t = read(), read()}, cpy[i] = t;
        sort(cpy + 1, cpy + 1 + K);
        u = unique(cpy + 1, cpy + 1 + K) - cpy - 1;
        for (reg int i = 1 ; i <= K ; i ++) da[i].y = lower_bound(cpy + 1, cpy + 1 + u, da[i].y) - cpy;
        sort(da + 1, da + 1 + K);
        for (reg int i = 1 ; i <= K ; i ++)
        {
            f[i] = query(da[i].y) + da[i].p;
            change(da[i].y, f[i]);
            ans = max(ans, f[i]);
        }
        cout << ans << endl;
        return 0;
    }
  • 相关阅读:
    [P1034][NOIP2001]一元三次方程求解 (二分)
    考前停课集训 Day7 嘞
    [P4995]跳跳!(贪心)
    [P4994]终于结束的起点 (递推)
    考前停课集训 Day6 垒
    [BZOJ1899][ZJOI2004]Lunch 午餐 (DP)
    考前停课集训 Day5 累
    任务查询系统 【主席树】
    主席树入门
    HNOI2002 营业额统计 平衡树模板题 【splay】
  • 原文地址:https://www.cnblogs.com/BriMon/p/9763699.html
Copyright © 2020-2023  润新知