HDU 4302 Holedox Eating

18 篇文章 0 订阅
1 篇文章 0 订阅

Holedox Eating

hdu 4302
有一个[0,l]区间,有一只毛毛虫,初始位置在0,现在又两种操作操作0 x 代表在x点放一块蛋糕,操作1代表毛毛虫要吃一块蛋糕:如果有蛋糕,那么毛毛虫将走到距离其最近的位置吃一块蛋糕。如果在其两边有两个距离其等距的蛋糕,那么毛毛虫将沿上次走的方向移动。如果没有蛋糕那么毛毛虫将待在原位置不动。现在给定M个操作,问毛毛虫的移动距离。
做法:
1.用线段树。线段树节点存储每个区间的放置有蛋糕的
最左点与最右点,对于0操作就是添加一个蛋糕,对于1操作就是先找到
移动的目标位置,然后减去一块蛋糕。
2.直接模拟,用set,快速查询,因为其有序。。代码短,速度快。


线段树版

/*
    author   : csuchenan
    prog     : hdu 4302
    algorithm: 线段树 节点保存该区间的最左与最右值,然后每次查询查询双向
    2012-10-20 16:41:23	Accepted	4302	421MS	5368K	4286 B	C++	csu_chenan
*/
#include <cstdio>
#include <cstring>
const int maxn = 100010;
#define INF 10000000
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define M(x, y) ((x+y)>>1)

struct Tree{
    int l, r;
    int mx, mn, sum;
}tree[maxn*4];

inline int max(int x, int y){
    if(x>y)
        return x;
    else
        return y;
}

inline int min(int x, int y){
    if(x<y)
        return x;
    else
        return y;
}

void build(int l, int r, int c){
    tree[c].l = l;
    tree[c].r = r;
    tree[c].mx = -INF;
    tree[c].mn = INF;
    tree[c].sum= 0;
    if(l == r)
        return ;
    build(l, M(l, r), L(c));
    build(M(l, r)+1, r, R(c));
}

void pushUp(int c){
    int l = L(c);
    int r = R(c);
    tree[c].mx = max(tree[l].mx, tree[r].mx);
    tree[c].mn = min(tree[l].mn, tree[r].mn);
    return ;
}
//d=0 means delete d=1 means add
void update(int p, int d, int c){
    if(tree[c].l == tree[c].r){
        if(d==1){
            tree[c].mx = p;
            tree[c].mn = p;
            tree[c].sum ++;
        }
        else{
            tree[c].sum --;
            if(tree[c].sum == 0){
                tree[c].mx = -INF;
                tree[c].mn = INF;
            }
        }
        return ;
    }
    int m = M(tree[c].l, tree[c].r);
    if(p <= m){
        update(p, d, L(c));
    }
    else{
        update(p, d, R(c));
    }
    pushUp(c);
}

//flag=1 means query left, so mx , flag=0 means query right, so mn;
int query(int l, int r, int c, int flag){
    if(tree[c].l==l && tree[c].r==r){
        if(flag==1)
            return tree[c].mx;
        else
            return tree[c].mn;
    }
    int m = M(tree[c].l, tree[c].r);
    if(r <= m){
        return query(l, r, L(c), flag);
    }
    else if(l > m){
        return query(l, r, R(c), flag);
    }
    else{
        int tmp = query(l, m, L(c), flag);
        int ans = query(m+1, r, R(c), flag);
        if(flag==1){
            return max(ans, tmp);
        }
        else{
            return min(ans, tmp);
        }
    }
}

int main(){
    int T, cas=1;
    int l, m;
    int c, x;
    int dir, p, ans;
//    freopen("test.in", "r", stdin);
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &l, &m);
        ans = p = 0;
        dir = 1;
        build(0, l, 1);
        for(int i = 0; i < m; i ++){
            scanf("%d", &c);
            if(c==0){
                scanf("%d", &x);
                update(x, 1, 1);
            }
            else{
                int lp = query(0, p, 1, 1);//left
                int rp = INF;
                if(p < l) // 注意这里。。。
                    rp = query(p+1, l, 1, 0);//right
                //stay there
                if(lp == p){
                    update(p, 0, 1);
                }
                //not found and stay there
                else if(lp < 0 && rp > l){
                }
                //right
                else if(lp < 0 && rp <= l){
                    dir = 1;
                    ans += rp - p;
                    p = rp;
                    update(p, 0, 1);
                }
                //left
                else if(lp >= 0 && rp > l){
                    dir = 0;
                    ans += p - lp;
                    p = lp;
                    update(p, 0, 1);
                }
                //both
                else if(lp >= 0 && rp <= l){
                    // right
                    if(p - lp > rp - p){
                        dir = 1;
                        ans += rp - p;
                        p = rp;
                    }
                    //left
                    else if(p - lp < rp - p){
                        dir = 0;
                        ans += p - lp;
                        p = lp;
                    }
                    else{
                        ans += p - lp;
                        if(dir==1){
                            p = rp;
                        }
                        else{
                            p = lp;
                        }
                    }
                    update(p, 0, 1);
                }
            }
        }
        printf("Case %d: %d\n", cas++, ans);
    }
    return 0;
}

set版

#include <cstdio>
#include <cstring>
#include <set>
using std::set;
const int maxn = 100005;
int num[maxn];
set<int> s;

int main(){
    int T, cas = 1;
    int c, a;
    int l, m;
    int dir, p, ans;
//    freopen("test.in","r", stdin);
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &l, &m);
        memset(num,0, sizeof(int) * (l + 2));
        ans = p = 0;
        dir = 1;
        s.clear();
        s.insert(0);
        for(int i = 1; i <= m; i ++){
            scanf("%d", &c);
            if(c==0){
                scanf("%d", &a);
                num[a] ++;
                s.insert(a);
            }
            else{
                int q = p;
                if(num[p] > 0){
                    num[p] --;
                    continue;
                }

                set<int>::iterator it1, it2;
                it1=it2=s.find(p);
                int lp = -1, rp = -1;
                if(it1 != s.begin()){
                    lp = *(--it1);
                }
                if(++it2 != s.end())
                    rp= *it2;
                if(lp==-1 && rp== -1)
                    continue;
                else{
                    if(lp==-1){
                        dir = 1;
                        ans += rp - p;
                        p = rp;
                        num[p] --;
                    }
                    else{
                        if(rp==-1){
                            dir = 0;
                            ans += p - lp;
                            p = lp;
                            num[p] --;
                        }
                        else{
                            int dl = p - lp;
                            int dr = rp - p;
                            if(dl==dr){
                                if(dir==1){
                                    p = rp;
                                    ans += dr;
                                    num[p] --;
                                }
                                else{
                                    p = lp;
                                    ans += dl;
                                    num[p] --;
                                }
                            }
                            else{
                                if(dl < dr){
                                    dir = 0;
                                    ans += dl;
                                    p = lp;
                                    num[p] --;
                                }
                                else{
                                    dir = 1;
                                    ans += dr;
                                    p = rp;
                                    num[p] --;
                                }
                            }
                        }
                    }
                }
                s.erase(q);
            }
        }
        printf("Case %d: %d\n", cas ++ , ans);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值