题解:
首先观察题面,直觉上对于一头奶牛,肯定要给它配pi和qi符合条件的草中两者尽量低的草,以节省下好草给高要求的牛。
实际上这是对的,但观察到两者尽量低这个条件并不明确,无法用于判断,因此要考虑一些其他的方法。
首先我们把牛和草都放在一个数组里,然后按照口感给它们排序。这样对于任意一头牛而言,口感符合要求的就只有在它前面的草。
排完序后,我们只需要在任意一头牛之前找到一个还没有被分配的,价格最低的符合要求的草即可。
为什么这样就不用考虑口感尽量低这个条件了呢?
因为对于后面的任意一只牛而言,在它前面的草的口感值大于要求,因此不管前面的牛怎么选择,剩下的草都是符合口感要求的,因此此时再去对口感值做限制就毫无意义了。
所以我们只需要在它前面的草中筛选出大于价格要求的,最便宜的草即可。
如果没有大于价格要求这一条件,显然我们可以用堆,但是由于这个条件限制,堆无法实现。
因此我们可以考虑用平衡树来实现它。
用STL是最简单的,当然也可以自己手写。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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\n"); 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\n", 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\n", ans); 156 } 157 158 int main() 159 { 160 // freopen("in.in", "r", stdin); 161 pre(); 162 work(); 163 // fclose(stdin); 164 return 0; 165 }