• 【贪心】bzoj1577: [Usaco2009 Feb]庙会捷运Fair Shuttle


    一类经典的线段贪心

    Description

    公交车一共经过N(1<=N<=20000)个站点,从站点1一直驶到站点N。K(1<=K<=50000)群奶牛希望搭乘这辆公交车。第i群牛一共有Mi(1<=Mi<=N)只.

    他们希望从Si到Ei去。
    公交车只能座C(1<=C<=100)只奶牛。而且不走重复路线,请计算这辆车最多能满足多少奶牛听要求。
    注意:对于每一群奶牛,可以部分满足,也可以全部满足,也可以全部不满足。

    Input

    第1行: 三个整数: K,N,C。 由空格隔开。

    第2..K+1行:第i+1行,告诉你第i组奶牛的信息: S_i, E_i and M_i。由空格隔开。

    Output

    一行:可以在庙会乘坐捷运的牛的最大头数

    HINT

    捷运可以把2头奶牛从展台1送到展台5,3头奶牛从展台5到展台8, 2头奶牛从展台8 到展台14,1头奶牛从展台9送到展台12,一头奶牛从展台13送到展台14, 一头奶牛从 14送到15。


    题目分析

    这种“线段贪心”,最经典的莫过于容量为1的情况。

    容量为1时,做法就是按照右端点排序,$O(n)$扫一遍选取不冲突的线段。这个贪心之所以不需要“反悔”,是因为价值和容量一一对应:每一时刻不论选哪一条线段,获得价值都是1.从这个角度上来说,所有线段是无差别的。

    想法自然但不正确的贪心1

    从容量为1的情况会想到:既然答案可以看做是c次互不影响的“容量为1”路径,那就做c次$O(n)$的贪心嘛。

    上图中,最优决策的确可以看做是c次互不影响的决策。但是当我们去选取线段时,会发现按照r端点排序的贪心策略在分配c组互不影响的决策上失效了。

    依然按照r排序的正确贪心2

    这里采用一种非形式化的语言描述这种贪心策略的正确性:

    对于总的安排来说,目标是让每一时刻容量都不要空闲;对于细的策略来说,因为这里线段可以拆开,所以目标是让选取的线段越少冲突越好。

    那么先按照r排序。排序后,当然是越靠前的线段越“好”。这里的“好”指的是,这条线段既把之前的容量利用起来;又对后面的线段产生较小的影响。

    实在不行可以假设这个结论就是对的……

    那么我是用永久标记线段树来维护这个贪心过程。

     1 #include<bits/stdc++.h>
     2 const int maxn = 50035;
     3 
     4 struct node
     5 {
     6     int l,r,v;
     7     bool operator < (node a) const
     8     {
     9         return r < a.r;
    10     }
    11 }edges[maxn];
    12 int k,n,c,ans;
    13 int f[maxn<<1],add[maxn<<1];
    14 
    15 int read()
    16 {
    17     char ch = getchar();
    18     int num = 0;
    19     bool fl = 0;
    20     for (; !isdigit(ch); ch=getchar())
    21         if (ch=='-') fl = 1;
    22     for (; isdigit(ch); ch=getchar())
    23         num = (num<<1)+(num<<3)+ch-48;
    24     if (fl) num = -num;
    25     return num;
    26 }
    27 int query(int rt, int L, int R, int l, int r, int hd)
    28 {
    29     if (L <= l&&r <= R){
    30         return f[rt]+hd;
    31     }
    32     int mid = (l+r)>>1, ans = 0;
    33     if (L <= mid) ans = std::max(query(rt<<1, L, R, l, mid, hd+add[rt]), ans);
    34     if (R > mid) ans = std::max(query(rt<<1|1, L, R, mid+1, r, hd+add[rt]), ans);
    35     return ans;
    36 }
    37 void pushup(int rt)
    38 {
    39     f[rt] = std::max(f[rt<<1], f[rt<<1|1])+add[rt];
    40 }
    41 void adds(int rt, int L, int R, int l, int r, int c)
    42 {
    43     if (L <= l&&r <= R){
    44         f[rt] += c, add[rt] += c;
    45         return;
    46     }
    47     int mid = (l+r)>>1;
    48     if (L <= mid) adds(rt<<1, L, R, l, mid, c);
    49     if (R > mid) adds(rt<<1|1, L, R, mid+1, r, c);
    50     pushup(rt);
    51 }
    52 int main()
    53 {
    54     k = read(), n = read(), c = read();
    55     for (int i=1; i<=k; i++)
    56         edges[i].l = read(), edges[i].r = read(), edges[i].v = read();
    57     std::sort(edges+1, edges+k+1);
    58     for (int i=1; i<=k; i++)
    59     {
    60         int delta = std::min(c-query(1, edges[i].l, edges[i].r, 1, n, 0), edges[i].v);
    61         ans += delta;
    62         if (delta)
    63             adds(1, edges[i].l, edges[i].r-1, 1, n, delta);
    64     }
    65     printf("%d
    ",ans);
    66     return 0;
    67 }

    END

  • 相关阅读:
    Linux下oracle数据库操作
    springcloud学习一
    nginx反向代理实现前后端分离
    GIT版本控制(码云)
    VUE环境搭建
    线程池的使用
    neo4j图形数据库实战
    idea 下tomcat字符集问题
    webservice客户端生成方式
    Spring声明式事务不回滚的问题
  • 原文地址:https://www.cnblogs.com/antiquality/p/9729794.html
Copyright © 2020-2023  润新知