51Nod-1461-稳定桌
2017-06-29 05:53
363 查看
ACM模版
首先,我们对每种代价进行建树,然后从大到小对长度进行排序,接着遍历一遍,枚举桌腿高度,不断添加删除的边,因为所有高于当前桌腿高度的都要删除(真正的从线段树中删除),然后判断低于当前桌腿高度的这些桌腿的数目是否少于当前高度的数量,如果是的话,直接更新结果,如果不是,那么我们需要从低于当前桌腿高度的桌腿中查找若干个代价最低的桌腿删除(并不是真的删除,只是查找线段树中的这部分结果而已),这个过程十分适合用线段树处理,所以呢,这个题就酱紫过了。
总而言之,这个题是一道可以用线段树优化的枚举贪心问题。
写这个代码时我遇见了一个极其隐秘的 bug,但是这个 bug 一点也不稀罕,这个 bug 是由于宏定义的 MIN 导致的。
我定义了一个 MIN(a,b) ((a)>(b)) ? (b):(a) 的宏定义,然后在代码中调用了,代码如下:
宏替换后就变成了这个,
如此一来,我的 query() 会多调用若干次,而代码中很清楚的是,这并不是单纯的访问,ld 会在访问时产生变化,影响下次的访问。
这个问题,让我找了一个多小时的 bug,虽然我宏定义这个玩意儿时格外注意了缺少括号所可能带来的 bug,但是我终究还是没有注意到函数重复调用上的 bug……
╮(╯▽╰)╭哎,像我这么粗心大意的人,还是少用宏定义吧,动不动就引入了这种极度隐秘的 bug,心塞( ⊙ o ⊙ )啊!
描述
题解
这个是 CF 上的原题改的,将 di 的数据放大了,所以不能普通的枚举代价了,而需要用数据结构优化处理,这里可以使用线段树搞搞事情,很意外。首先,我们对每种代价进行建树,然后从大到小对长度进行排序,接着遍历一遍,枚举桌腿高度,不断添加删除的边,因为所有高于当前桌腿高度的都要删除(真正的从线段树中删除),然后判断低于当前桌腿高度的这些桌腿的数目是否少于当前高度的数量,如果是的话,直接更新结果,如果不是,那么我们需要从低于当前桌腿高度的桌腿中查找若干个代价最低的桌腿删除(并不是真的删除,只是查找线段树中的这部分结果而已),这个过程十分适合用线段树处理,所以呢,这个题就酱紫过了。
总而言之,这个题是一道可以用线段树优化的枚举贪心问题。
写这个代码时我遇见了一个极其隐秘的 bug,但是这个 bug 一点也不稀罕,这个 bug 是由于宏定义的 MIN 导致的。
我定义了一个 MIN(a,b) ((a)>(b)) ? (b):(a) 的宏定义,然后在代码中调用了,代码如下:
ans = MIN(ans, sum + query(1, MAXN, 1));
宏替换后就变成了这个,
ans = ans > (sum + query(1, MAXN, 1)) ? (sum + query(1, MAXN, 1)) : ans;
如此一来,我的 query() 会多调用若干次,而代码中很清楚的是,这并不是单纯的访问,ld 会在访问时产生变化,影响下次的访问。
这个问题,让我找了一个多小时的 bug,虽然我宏定义这个玩意儿时格外注意了缺少括号所可能带来的 bug,但是我终究还是没有注意到函数重复调用上的 bug……
╮(╯▽╰)╭哎,像我这么粗心大意的人,还是少用宏定义吧,动不动就引入了这种极度隐秘的 bug,心塞( ⊙ o ⊙ )啊!
代码
#include <cstdio> #include <iostream> #include <algorithm> #define lson k << 1 #define rson k << 1 | 1 using namespace std; typedef long long ll; const int MAXN = 1e5 + 10; const ll INF = 0x3f3f3f3f3f3f3f3f; template <class T> inline void scan_d(T &ret) { char c; ret = 0; while ((c = getchar()) < '0' || c > '9'); while (c >= '0' && c <= '9') { ret = ret * 10 + (c - '0'), c = getchar(); } } struct leg { int l, d; bool operator < (const leg &b) const { return l > b.l; } } L[MAXN]; struct node { int c; ll v; } tree[MAXN << 2]; int n; int cnt[MAXN]; // 每种代价的数量 inline void pushup(int k) { tree[k].v = tree[lson].v + tree[rson].v; tree[k].c = tree[lson].c + tree[rson].c; } void build(int l, int r, int k) { if (l == r) { if (cnt[l]) { tree[k].v = 1ll * (tree[k].c = cnt[l]) * l; } return ; } int m = (l + r) >> 1; build(l, m, lson); build(m + 1, r, rson); pushup(k); } int ld, flag; void update(int l, int r, int k) { if (flag == -1) { tree[k].c--, tree[k].v -= ld; } else { tree[k].c++, tree[k].v += ld; } if (l == r) { return ; } int m = (l + r) >> 1; if (ld <= m) { update(l, m, lson); } else { update(m + 1, r, rson); } } ll query(int l, int r, int k) { if (l == r) { return 1ll * ld * l; } int m = (l + r) >> 1; if (tree[lson].c >= ld) { return query(l, m, lson); } else { ld -= tree[lson].c; return tree[lson].v + query(m + 1, r, rson); } } int main() { scan_d(n); ll ans = INF, sum = 0; for (int i = 1; i <= n; i++) { scan_d(L[i].l); } for (int i = 1; i <= n; i++) { scan_d(L[i].d); cnt[L[i].d]++; } build(1, MAXN, 1); sort(L + 1, L + n + 1); ll tmp = 0; for (int i = 1, j; i <= n; i = j + 1) { if (sum >= ans) { break; } sum += tmp; j = i; tmp = ld = L[i].d; flag = -1; update(1, MAXN, 1); while (j < n && L[j + 1].l == L[i].l) { tmp += (ld = L[++j].d); flag = -1; update(1, MAXN, 1); } int num = j - i; // 当前高度桌腿的数目 if (n - j <= num) { ans = min(ans, sum); break; } else { ld = n - j - num; ans = min(ans, sum + query(1, MAXN, 1)); } } cout << ans << endl; return 0; }
相关文章推荐
- 51nod 1461 稳定桌[线段树]
- 【51nod】1461 稳定桌 扫描线+线段树
- 51nod 1461 稳定桌
- 51nod 1461 稳定桌
- 51nod 1461 稳定桌
- 51nod 1461 稳定桌【扫描线】【线段树】
- 51Nod-1530-稳定方块
- 51nod 1461
- 51Nod 1530 稳定方块
- [堆]51 Nod 1461——稳定桌
- 51nod 1015 水仙花数
- 51nod 1035 最长的循环节
- 51nod 1102 面积最大的矩形
- 51nod 1186 质数检测 V2
- 51nod 1298 圆与三角形
- 51nod 1503 猪和回文
- 51nod 1381 硬币游戏
- 51nod 1305 Pairwise Sum and Divide
- 51nod-【1067 Bash游戏 V2】
- 51nod-1394 差和问题(树状数组)