HDU 4302 Holedox Eating (線段樹模擬)

題意:一個老鼠在一條長度爲L的直線上跑,吃蛋糕,老鼠只能沿直線移動。開始時沒有蛋糕,老鼠的初始位置是0.ui

有兩個操做,0 x 表明在位置x添加一個蛋糕; 1 表明老鼠想吃蛋糕。老鼠每次都會選擇離本身最近的點,若是兩邊距離相同,老鼠優先選擇與本身當前移動方向相同的點。spa

求最終移動的總距離。code

題解:線段樹單點修改+查詢區間端點。blog

設當前位置爲pos,每次查詢區間[0, pos]的最右端和區間[pos, L]的最左端,比較選擇哪一個更近。ip

詳細題解見代碼註釋。string

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>

#define lson l, m, rt << 1
#define rson m+1, r, rt << 1 | 1

#define LEFT  0
#define RIGHT 1

using std::min;
using std::max;
using std::abs;

const int MAXN = 100010;
const int INF = 1 << 30;

int tr[MAXN << 2];             //標記哪一個點有蛋糕
int left[MAXN << 2];           //標記區間[l, r]內有蛋糕的最左端點
int right[MAXN << 2];          //標記區間[l, r]內有蛋糕的最右端點
int N, S;
int findL, findR;              //標記查找到的任意區間[l, r]中有蛋糕的最左端和最右端

void PushUp( int rt )
{
    int lc = rt << 1;
    int rc = rt << 1 | 1;
    left[rt]  = min( left[lc], left[rc] );
    right[rt] = max( right[lc], right[rc] );
    return;
}

void build( int l, int r, int rt )     //建樹
{
    tr[rt] = 0;                        //每一個點初始蛋糕數目爲0
    left[rt] = INF;
    right[rt] = -INF;
    if ( l == r ) return;
    int m = ( l + r ) >> 1;
    build( lson );
    build( rson );
    return;
}

void Update( int pos, int v, int l, int r, int rt )  //更新
{
    if ( l == pos && r == pos )
    {
        tr[rt] += v;                                 //更新該點的蛋糕數目
        if ( tr[rt] == 0 )                           //若是這一點沒有蛋糕了
        {
            left[rt]  = INF;
            right[rt] = -INF;
        }
        else                                         //若是這一點有蛋糕
        {
            left[rt] = l;
            right[rt] = l;
        }
        return;
    }

    int m = ( l + r ) >> 1;
    if ( pos <= m ) Update( pos, v, lson );
    else            Update( pos, v, rson );
    PushUp( rt );
    return;
}

void Query( int L, int R, int l, int r, int rt )     //查詢
{
    if ( L <= l && r <= R )
    {
        findL = min( left[rt], findL );
        findR = max( right[rt], findR );
        return;
    }
    int m = ( l + r ) >> 1;
    if ( L <= m ) Query( L, R, lson );
    if ( R > m )  Query( L, R, rson );
    return;
}

int main()
{
    int T, cas = 0;
    scanf( "%d", &T );
    while ( T-- )
    {
        scanf( "%d%d", &N, &S );
        ++N;                             //原題目中pipe長度爲L,編號爲0-L,其實是有(L+1)個點,
                                         //以前沒注意,RE了一次,在這裏我把每一個點編號爲1-(L+1)

        int curPos = 1;                  //當前位置
        int curDirection = RIGHT;        //當前方向
        int sum = 0;                     //移動總路程

        build( 1, N, 1 );                //建樹

        while ( S-- )
        {
            //printf("**************curPos=%d curDir=%d\n", curPos, curDirection );
            int op, pos;
            scanf( "%d", &op );
            if ( op == 0 )
            {
                scanf( "%d", &pos );
                Update( pos+1, 1, 1, N, 1 );
            }
            else
            {
                bool find = false;
                int findpos;

                if ( curDirection == LEFT )                   //若是當前方向向左
                {
                    int LL, RR;
                    findL = INF;
                    findR = -INF;
                    Query( 1, curPos, 1, N, 1 ), LL = findR;  //向左走,找離當前點最近的右端點
                    findL = INF;
                    findR = -INF;
                    Query( curPos, N, 1, N, 1 ), RR = findL;  //向右走,找離當前點最近的左端點

                    if ( LL == -INF && RR == INF )            //兩邊都沒有蛋糕
                    {
                        find = false;
                    }
                    else if ( LL == -INF && RR != INF )       //只有右邊有蛋糕
                    {
                        find = true;
                        findpos = RR;
                        curDirection = RIGHT;
                    }
                    else if ( LL != -INF && RR == INF )       //只有左邊有蛋糕
                    {
                        find = true;
                        findpos = LL;
                        curDirection = LEFT;
                    }
                    else                                      //兩邊都有蛋糕
                    {
                        find = true;
                        if ( curPos - LL <= RR - curPos )     //注意等號,兩邊距離相等時優先選擇左邊
                        {
                            findpos = LL;
                            curDirection = LEFT;
                        }
                        else
                        {
                            findpos = RR;
                            curDirection = RIGHT;
                        }
                    }

                    //printf("LEFT: ");
                }
                else
                {
                    int LL, RR;
                    findL = INF;
                    findR = -INF;
                    Query( curPos, N, 1, N, 1 ), RR = findL;
                    findL = INF;
                    findR = -INF;
                    Query( 1, curPos, 1, N, 1 ), LL = findR;

                    if ( LL == -INF && RR == INF )
                    {
                        find = false;
                    }
                    else if ( LL == -INF && RR != INF )
                    {
                        find = true;
                        findpos = RR;
                        curDirection = RIGHT;
                    }
                    else if ( LL != -INF && RR == INF )
                    {
                        find = true;
                        findpos = LL;
                        curDirection = LEFT;
                    }
                    else
                    {
                        find = true;
                        if ( curPos - LL < RR - curPos )        //注意沒有等號,兩邊距離相等時優先選擇右邊
                        {
                            findpos = LL;
                            curDirection = LEFT;
                        }
                        else
                        {
                            findpos = RR;
                            curDirection = RIGHT;
                        }
                    }

                    //printf("RIGHT: ");
                }
                //printf( "findL=%d findR=%d\n", findL, findR );

                //printf( "findpos = %d\n", findpos );
                if ( find )
                {
                    sum += abs( findpos - curPos );
                    curPos = findpos;
                    Update( findpos, -1, 1, N, 1 );
                }
            }
        }

        printf( "Case %d: %d\n", ++cas, sum );
    }
    return 0;
}
相關文章
相關標籤/搜索