• [USACO07DEC]美食的食草动物Gourmet Grazers


    ~~~题面~~~

    题解:

      首先观察题面,直觉上对于一头奶牛,肯定要给它配pi和qi符合条件的草中两者尽量低的草,以节省下好草给高要求的牛。

      实际上这是对的,但观察到两者尽量低这个条件并不明确,无法用于判断,因此要考虑一些其他的方法。

      首先我们把牛和草都放在一个数组里,然后按照口感给它们排序。这样对于任意一头牛而言,口感符合要求的就只有在它前面的草。

      排完序后,我们只需要在任意一头牛之前找到一个还没有被分配的,价格最低的符合要求的草即可。

      为什么这样就不用考虑口感尽量低这个条件了呢?

      因为对于后面的任意一只牛而言,在它前面的草的口感值大于要求,因此不管前面的牛怎么选择,剩下的草都是符合口感要求的,因此此时再去对口感值做限制就毫无意义了。

      所以我们只需要在它前面的草中筛选出大于价格要求的,最便宜的草即可。

      如果没有大于价格要求这一条件,显然我们可以用堆,但是由于这个条件限制,堆无法实现。

      因此我们可以考虑用平衡树来实现它。

      用STL是最简单的,当然也可以自己手写。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define R register int
      4 #define AC 220000
      5 #define LL long long
      6 
      7 int n, m, cnt;
      8 LL ans;
      9 
     10 struct node{
     11     int cost, taste;
     12     bool who;
     13 }p[AC];
     14 
     15 struct splay_tree{
     16     int root, tot, go;
     17     int son[AC][2], father[AC], cnt[AC], Size[AC], val[AC];
     18     
     19     inline void update(int x)
     20     {
     21         Size[x] = Size[son[x][0]] + Size[son[x][1]] + cnt[x];
     22     }
     23     
     24     void rotate(int x)
     25     {
     26         int y = father[x];
     27         int z = father[y];
     28         int k = (son[y][1] == x);
     29         father[x] = z;
     30         son[z][son[z][1] == y] = x;
     31         father[son[x][k ^ 1]] = y;
     32         son[y][k] = son[x][k ^ 1];
     33         father[y] = x;
     34         son[x][k ^ 1] = y;
     35         update(y), update(x);
     36     }
     37     
     38     void splay(int x, int goal)
     39     {
     40         if(!x) return ;
     41         while(father[x] != goal)
     42         {
     43             int y = father[x], z = father[y];
     44             if(z != goal) 
     45                 (son[y][0] == x) ^ (son[z][0] == y) ? rotate(x) : rotate(y);
     46             rotate(x);
     47         }
     48         update(x);
     49         if(!goal) root = x;
     50     }
     51     
     52     void find(int x, int w)//找到这个点的前驱,并splay到root
     53     {
     54         if(!x) return ;
     55         if(val[x] >= w)
     56         {
     57             if(!go || val[x] < val[go]) go = x;
     58             find(son[x][0], w);
     59         } 
     60         else find(son[x][1], w);
     61     }
     62     
     63     int found(int k)//找根的前驱后继
     64     {
     65         int now = root;
     66         now = son[now][k];
     67         while(son[now][k ^ 1]) now = son[now][k ^ 1];
     68         return now;
     69     }
     70     
     71     void get(int x)
     72     {
     73         go = 0, find(root, x);
     74         if(!go) 
     75         {
     76             printf("-1
    ");
     77             exit(0);
     78         }
     79         splay(go, 0);
     80         ans += val[go];
     81         if(cnt[go] > 1) 
     82         {
     83             --cnt[go];
     84             update(go);
     85             return ;
     86         }
     87         int before = found(0), behind = found(1);
     88         if(!before && !behind) root = 0;
     89         else if(!before) root = son[root][1], father[root] = 0;
     90         else if(!behind) root = son[root][0], father[root] = 0;
     91         else splay(before, 0), splay(behind, before);
     92         son[behind][0] = 0;
     93     }
     94     
     95     void insert(int x)//插入一个点
     96     {
     97         int now = root, fa = 0;
     98         while(now && val[now] != x)
     99         {
    100             fa = now;
    101             now = son[now][x > val[now]];
    102         }
    103         if(now) cnt[now] ++;
    104         else
    105         {
    106             now = ++ tot;
    107             if(fa) son[fa][x > val[fa]] = now;
    108             father[now] = fa;
    109             val[now] = x;
    110             cnt[now] = Size[now] = 1;
    111             if(fa) update(fa);
    112         }
    113         splay(now, 0);
    114     }
    115 }s;
    116 
    117 inline int read()
    118 {
    119     int x = 0;char c = getchar();
    120     while(c > '9' || c < '0') c = getchar();
    121     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    122     return x;
    123 }
    124 
    125 inline bool cmp(node a, node b)
    126 {
    127     if(a.taste != b.taste) return a.taste > b.taste;
    128     else return a.cost > b.cost;
    129 }
    130 
    131 void pre()
    132 {
    133     int a, b;
    134     n = read(), m = read();
    135     for(R i = 1; i <= n; i ++)
    136     {
    137         a = read(), b = read();
    138         p[++cnt] = (node){a, b, 0}; 
    139     }
    140     for(R i = 1; i <= m; i ++)
    141     {
    142         a = read(), b = read();
    143         p[++cnt] = (node){a, b, 1};
    144     }    
    145     sort(p + 1, p + cnt + 1, cmp);
    146 //    for(R i = 1; i <= cnt; i ++)
    147     //    printf("%d %d %d
    ", p[i].cost, p[i].taste, p[i].who);
    148 }
    149 
    150 void work()
    151 {
    152     for(R i = 1; i <= cnt; i ++)
    153         if(!p[i].who) s.get(p[i].cost);
    154         else s.insert(p[i].cost);
    155     printf("%lld
    ", ans);
    156 }
    157 
    158 int main()
    159 {
    160 //    freopen("in.in", "r", stdin);
    161     pre();
    162     work();
    163 //    fclose(stdin);
    164     return 0;
    165 }
    View Code

     

  • 相关阅读:
    SQL利用Case When Then多条件判断
    SQL 中LTrim、RTrim与Trim的用法
    SELECT 与 SET 对变量赋值的区别(存储过程)
    exec/sp_executesql语法
    SQLServer : EXEC和sp_executesql的区别
    使用系统监视器监视系统性能
    Centos6.5下OpenLdap搭建(环境配置+双机主从配置+LDAPS+enable SSHA)
    迁移与裁剪linux系统
    Windows Server 2008 R2远程桌面服务配置和授权激活(转)
    cookie、session、sessionid 与jsessionid(转)
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9615541.html
Copyright © 2020-2023  润新知