hdu4302 Holedox Eating(线段树单点更新,单点查询or multiset)

Holedox Eating

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3407    Accepted Submission(s): 1165


Problem Description
Holedox is a small animal which can be considered as one point. It lives in a straight pipe whose length is L. Holedox can only move along the pipe. Cakes may appear anywhere in the pipe, from time to time. When Holedox wants to eat cakes, it always goes to the nearest one and eats it. If there are many pieces of cake in different directions Holedox can choose, Holedox will choose one in the direction which is the direction of its last movement. If there are no cakes present, Holedox just stays where it is.
 

Input
The input consists of several test cases. The first line of the input contains a single integer T (1 <= T <= 10), the number of test cases, followed by the input data for each test case.The first line of each case contains two integers L,n(1<=L,n<=100000), representing the length of the pipe, and the number of events.
The next n lines, each line describes an event. 0 x(0<=x<=L, x is a integer) represents a piece of cake appears in the x position; 1 represent Holedox wants to eat a cake.
In each case, Holedox always starts off at the position 0.
 

Output
Output the total distance Holedox will move. Holedox don’t need to return to the position 0.
 

Sample Input
3 10 8 0 1 0 5 1 0 2 0 0 1 1 1 10 7 0 1 0 5 1 0 2 0 0 1 1 10 8 0 1 0 1 0 5 1 0 2 0 0 1 1
 

Sample Output
Case 1: 9 Case 2: 4 Case 3: 2
 

Author
BUPT
 

Source
 
题意:在坐标[0,n]上会随机出现一些cake,输入 0 x  表示在坐标 x 处有一个cake,1 表示吃掉离当前最近的一个cake,如果左右相等则和上次移动方向一致, 初始位置在0处,方向朝右边。
 
思路:这题的做法有很多,比如可以维护2个单调队列(栈),还可以用STL中的multiset ,因为我最近想多练练线段数,就用线段数做了。
 
代码:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;

#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , mid
#define rson rs , mid + 1 , r
#define root 1 , 1 , n
#define rt o , l , r

#define LL long long
const int N = 100100;
const int inf = 100000000;
struct node
{
    int le,re,lazy;
    int cun;
} s[N*4];

void build (int o , int l , int r)
{
    s[o].le = l,s[o].re = r;
    s[o].cun = 0;
    if (l == r)
    {
        return;
    }
    int mid = ( l + r ) >> 1;
    build(lson);
    build(rson);
}
void update(int o , int x, int v)
{
    if(s[o].le == s[o].re && s[o].le == x)
    {
        s[o].cun += v;
        return ;
    }
    int mid = ( s[o].le + s[o].re ) >> 1;
    if(x <= mid)
        update(ls, x, v);
    else
        update(rs, x, v);
    s[o].cun = s[ls].cun || s[rs].cun;
}
int query1(int o, int l, int r)
{
    if(r < s[o].le || l > s[o].re)return -1;
    if(s[o].cun == 0)return -1;
    int ans = 0;
    if(s[o].le == s[o].re)
    {
        if(s[o].cun)
            return s[o].le;
        else
            return -1;
    }
    int mid = ( s[o].le + s[o].re ) >> 1;
        ans = query1(ls, l, r);
    if(ans == -1)
        ans = query1(rs, l, r);
    return ans;
}
int query2(int o, int l, int r)
{
    if(r < s[o].le || l > s[o].re)return -1;
    if(!s[o].cun)return -1;
    int ans = 0;
    if(s[o].le == s[o].re)
    {
        if(s[o].cun)
            return s[o].le;
        else
            return -1;
    }
    int mid = ( s[o].le + s[o].re ) >> 1;
        ans = query2(rs, l, r);
    if(ans == -1)
        ans = query2(ls, l, r);
    return ans;
}
int main()
{
    //freopen("in.txt","r",stdin);
    int L,q,t,op,x,next,len, cas = 0;
    scanf("%d",&t);
    while(t--)
    {
        cas++;
        int now = 0, dir = 0, sum = 0;//刚开始朝右边
        scanf("%d%d",&L,&q);
        build(1,0,L);//这里居然是0~L。。害得我找了半天错
        for(int i=1; i<=q; i++)
        {
            scanf("%d",&op);
            if(op == 0)
            {
                scanf("%d",&x);
                update(1,x,1);
            }
            else
            {
                int l = query2(1,0,now);
                int r = query1(1,now,L);
                if(l == -1 && r != -1) l = -inf;
                if(r == -1 && l != -1) r = inf;
                if(r == -1 && l == -1continue;
                int l_en = now - l;
                int r_en = r - now;
                if((l_en < r_en)||(l_en == r_en && dir == 1))
                {
                    now = l;
                    len = l_en;
                    dir = 1;
                }
                else //((l_en > r_en)||(l_en == r_en && dir == 0))
                {
                    now = r;
                    len = r_en;
                    dir = 0;
                }
                sum += len;
                update(1,now,-1);
            }
        }
        printf("Case %d: %d\n",cas,sum);
    }
    return 0;
}
View Code
 
顺便贴个别人写的用multiset, 比线段数简短多了....我以前接触过multiset,用的还不熟把。。下次要整理下
 
#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#define MIN -20000000
#define MAX 20000000
using namespace std;

int main()
{
    int test,n,m,i,k=1,key,t,p,ans,now;
    scanf("%d",&test);
    while(test--)
    {
        multiset<int>ms;
        ms.clear();
        multiset<int>::iterator it,ita,itb;
        scanf("%d %d",&n,&m);
        ms.insert(MIN);
        ms.insert(MAX);
        ans=0;
        p=1;
        now=0;
        for(i=0; i<m; i++)
        {
            scanf("%d",&key);
            if(key==0)
            {
                scanf("%d",&t);
                ms.insert(t);
            }
            else
            {
                ita=itb=ms.lower_bound(now);//大于等于now的最小值
                ita--;
                if(*itb==now)
                {
                    ms.erase(itb);
                    continue;
                }
                if(*ita==MIN&&*itb==MAX) continue;
                if(now-*ita<*itb-now)
                {
                    ans+=(now-*ita);
                    p=0;
                    now=*ita;
                    ms.erase(ita);
                }
                else if(now-*ita>*itb-now)
                {
                    ans+=(*itb-now);
                    p=1;
                    now=*itb;
                    ms.erase(itb);
                }
                else
                {
                    ans+=(now-*ita);
                    if(p==0)
                        now=*ita,ms.erase(ita);
                    else
                        now=*itb,ms.erase(itb);
                }
            }
        }
        printf("Case %d: %d\n",k++,ans);
    }
    return 0;
}
View Code
 
posted @ 2015-02-22 15:27  Doli  阅读(112)  评论(0)    收藏  举报