HDU 4302 Holedox Eating(线段树/优先队列/multiset)
来源:互联网 发布:淘宝仓库在哪里找 编辑:程序博客网 时间:2024/06/05 17:48
题意:一条线段,在某些时刻上面的某些点会随机出现蛋糕。某种动物最初在0位置,在该动物想吃蛋时,它会跑到离他最近的蛋糕那里;如果有两个蛋糕与它的距离相同,就按照上次前进的方向走。输出它走过的总路程。
其实就是个水题,然而坑了一天,交了两页的记录 - - 写个博客纪念下
赛上用线段树区间最值过的,赛后看题解提到也可以线段树 + 二分做,又听说了 pq 和 multiset 的版本,就写了一发 pq,结果有个地方觉得写得不对但还是莫名AC了,觉得奇怪就坑了一下午 - - 还好最后终于找到了原因,并且用下面的数据叉掉了集训队里一个汉子的AC代码……这里output应该是26~
关于这个case和这个隐蔽修改方向导致WA的问题的解释以及multiset版本的代码,详见 lwt学长哒博客
总之,写代码前一定要思考清楚,要写出美观不易错的代码~
1 20 13 0 4 1 0 3 1 0 3 1 0 1 0 5 0 20 1 1 1 1
- 线段树区间最值
网上思路较多,就不细说了 - -
//赛上的线段树区间最值版#include <algorithm>#include <cctype>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <map>#include <queue>#include <string>#define ALL(v) v.begin(), v.end()#define CLR(array) memset(array, 0, sizeof(array))#define DEBUG cout << "bug "#define Fr first#define FOR(i, n) for(int i = 0; i < n; i++)#define MEM(array) memset(array, 0x3f, sizeof(array))#define ls id << 1#define lson id << 1, l, m#define OFF(array) memset(array, -1, sizeof(array))#define PR(x) cout << #x << " = " << x << " "#define PRLN(x) cout << #x << " = " << x << endl#define rep(i, a, b) for(int i = a; i <= b; i++)#define root 1, 1, n#define rs id << 1 | 1#define rson id << 1 | 1, m + 1, r#define Rep(i, a, b) for(int i = a; i >= b; i--)#define repk(i, a, b) for(i = a; i <= b; i++)#define Repk(i, a, b) for(i = a; i >= b; i--)#define Sc second#define SZ size()using namespace std;typedef long long ll;typedef pair<int, int> P;const int inf = 0x3f3f3f3f, maxn = 1e5 + 5;struct Node { int lc, rc, cnt; //这里因为某点上可能有多个cake,所以还记录了区间内的cake数,其实单开数组记录每个点的cake数也可以} tree[maxn << 2];int lef, rig;void build(int id, int l, int r) { tree[id].lc = inf; tree[id].cnt = 0; tree[id].rc = -inf; if(l == r) return; int m = l + r >> 1; build(lson); build(rson);}void push_up(int id) { Node& now = tree[id]; now.lc = min(tree[ls].lc, tree[rs].lc); now.rc = max(tree[ls].rc, tree[rs].rc);}void update(int id, int l, int r, int pos, int d) { Node& now = tree[id]; now.cnt += d; if(l == r) { if(now.cnt) now.lc = now.rc = l; else { now.lc = inf; now.rc = -inf; } return; } int m = l + r >> 1; if(pos <= m) update(lson, pos, d); else update(rson, pos, d); push_up(id);}void query(int id, int l, int r, int a, int b, int op) { if(!tree[id].cnt) return; if(a <= l && r <= b) { if(op) rig = min(rig, tree[id].lc); else lef = max(lef, tree[id].rc); return; } int m = l + r >> 1; if(a <= m) query(lson, a, b, op); if(b > m) query(rson, a, b, op);}ll solve(void) { int n, q, a, b; ll ans = 0; int pre = 1, now = 1; scanf("%d%d", &n, &q); n++; build(root); while(q--) { scanf("%d", &a); if(a) { int goal; lef = -inf, rig = inf; query(root, 1, now, 0); query(root, now + 1, n, 1); if(now - lef != rig - now) goal = now - lef < rig - now ? lef : rig; else goal = pre > 0 ? rig : lef; if(abs(goal) == inf) continue; update(root, goal, -1); ans += abs(goal - now); if(goal > now) pre = 1; else if(goal < now) pre = -1; now = goal; } else { scanf("%d", &b); update(root, b + 1, 1); } } return ans;}int main(void) { int t, kase = 0; scanf("%d", &t); while(t--) printf("Case %d: %I64d\n", ++kase, solve()); return 0;}
- 然后是二分版本哒~可以不记录区间最值,只要记录区间内cake数就可以了,但是要写两个query,不太好看。
思路是每次查询到某个区间时,如果当前区间内没有cake,直接返回。如果要查找区间最右边的值,就优先查找右子树,然后才是左子树,查找区间左值类比即可。
不过,网上虽然有人提了这个思路,但是几乎没有清晰代码,所以也贴下~
// 二分版本~// 省略头文件50行const int inf = 0x3f3f3f3f, maxn = 1e5 + 5;int sum[maxn << 2];void build(int id, int l, int r) { sum[id] = 0; if(l == r) return; int m = l + r >> 1; build(lson); build(rson);}void update(int id, int l, int r, int pos, int d) { sum[id] += d; if(l == r) return; int m = l + r >> 1; if(pos <= m) update(lson, pos, d); else update(rson, pos, d);}int queryl(int id, int l, int r, int a, int b) { // 查找区间最左边的cake的位置,没有则返回inf if(l == r) return l; int m = l + r >> 1; int res = inf; if(a <= m && sum[ls]) res = queryl(lson, a, b); if(res == inf && b > m && sum[rs]) res = queryl(rson, a, b); return res;}// 注意两个query的区别int queryr(int id, int l, int r, int a, int b) { // 查找区间最右边的cake的位置,没有则返回 -inf if(l == r) return l; int m = l + r >> 1; int res = -inf; if(b > m && sum[rs]) res = queryr(rson, a, b); if(res == -inf && a <= m && sum[ls]) res = queryr(lson, a, b); return res;}ll solve(void) { int n, q, a, b; ll ans = 0; int pre = 1, now = 1; scanf("%d%d", &n, &q); n++; build(root); while(q--) { scanf("%d", &a); if(!a) { scanf("%d", &b); update(root, b + 1, 1); } else { int goal, lef, rig; lef = queryr(root, 1, now); rig = queryl(root, now + 1, n); if(now - lef != rig - now) goal = now - lef < rig - now ? lef : rig; else goal = pre > 0 ? rig : lef; if(abs(goal) == inf) continue; GOTO: update(root, goal, -1); ans += abs(goal - now); if(goal > now) pre = 1; else if(goal < now) pre = -1; now = goal; } } return ans;}int main(void) { int t, kase = 0; scanf("%d", &t); while(t--) printf("Case %d: %I64d\n", ++kase, solve()); return 0;}
- pq版本也来一发,网上代码也很多,不细说了 - -
不过说实话,用两个pq维护虽然听上去很机智,但是代码比较丑 也可能是我写的不好看吧 - - 感觉 multiset 或者 map 写会更简单
// pq 版~const int inf = 0x3f3f3f3f, maxn = 1e5 + 5;ll solve(void) { priority_queue <int> pql; priority_queue <int, vector<int>, greater<int> > pqr; int n, q, a, b; ll ans = 0; int pre = 1, now = 0; scanf("%d%d", &n, &q); while(q--) { scanf("%d", &a); if(!a) { scanf("%d", &b); if(b >= now) pqr.push(b); else pql.push(b); } else { int choice = 1, lef = -inf, rig = inf; if(pql.size()) lef = pql.top(); if(pqr.size()) rig = pqr.top(); if(now - lef != rig - now) { if(now - lef < rig - now) choice = -1; } else choice = pre; if(choice > 0 && rig != inf) { pqr.pop(); ans += rig - now; if(rig != now) pre = choice; now = rig; } else if(choice < 0 && lef != -inf) { pql.pop(); ans += now - lef; pre = choice; now = lef; } } } return ans;}int main(void) { int t, kase = 0; scanf("%d", &t); while(t--) printf("Case %d: %I64d\n", ++kase, solve()); return 0;}
0 0
- HDU 4302 Holedox Eating(线段树/优先队列/multiset)
- hdu 4302 Holedox Eating(优先队列模拟或线段树)
- HDU 4302 Holedox Eating (multiset模拟)
- HDU 4302 Holedox Eating(multiset)
- hdu - 4302 Holedox Eating (优先队列)
- HDU 4302 Holedox Eating (两个优先队列)
- hdu 4302 Holedox Eating(优先队列)
- HDU - 4302 :Holedox Eating ,线段树、树状数组+二分,优先队列
- 线段树,堆,multiset:Holedox Eating
- HDU 4302 Holedox Eating (线段树)
- hdu - 4302 - Holedox Eating - 线段树
- HDOJ 4302 - Holedox Eating 优先队列
- HDOJ Holedox Eating 4302(优先队列)
- hdoj 4302 Holedox Eating 【优先队列】
- Hdoj 4302 Holedox Eating 【multiset】
- HDU4302 Holedox Eating 优先队列
- hdu 4302 Holedox Eating
- HDU 4302 holedox eating
- java学习:Hashtable,ArrayList,vector示例程序
- iis调试错误大全
- Android程序员必备精品资源
- 【JavaScript】学习笔记(对象的访问,创建;for-in循环)
- Java初学笔记
- HDU 4302 Holedox Eating(线段树/优先队列/multiset)
- 设计模式-策略模式
- POJ 题目2082 Terrible Sets(单调栈)
- 在SAE上使用wx_sample.php获取token失败问题
- Android studio中配置androidannotations框架
- Android 项目 利用Gradle 一键打包
- android:AssetManager
- 面试心得 上海 - 北京
- Word Break