poj 2892 Tunnel Warfare(线段树)

题意:有N个点是连通的,现在给出Q个操作,D是破坏这个点,R是恢复最近被破坏的点,Q是询问与这个点相连的点的个数。

思路:这题与上次比赛的最后一题有点相似,比赛的题是让求从该点往后的相同的字符的个数,而这题是求与这个点相连的点,包括前后。其实线段树也很好理解,节点设四个标记,最左端点,最右端点,从左端点开始,与左端点相连的点的个数,从右端点开始,与右端点相连的点的个数,随时更新,查询时是,先找到最左端相连的区间,然后不断向右找到不相连的点。

呃, 还是看代码吧。

代码:

View Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stack>
#define  N 50005
using namespace std ;

struct node
{
    int ll , rr ;
    int lval , rval ;//左右相连的点的个数
}p[4*N] ;

int vis[N] ;
int n , m ;
stack<int>st;//栈,用来存放破坏的点

//建树
void make_tree( int id , int l , int r )
{
    p[id].ll = l ;
    p[id].rr = r ;
    p[id].lval = p[id].rval = ( r - l + 1 );
    if ( l == r )
    return ;
    int mid = ( l + r )/2 ;
    make_tree( 2*id , l , mid );
    make_tree( 2*id+1 , mid + 1 , r );
}

//更新
void update( int id , int num , int flag )
{
    if( p[id].ll == p[id].rr )
    {
        p[id].lval = p[id].rval = flag ;
        vis[p[id].ll] = flag ;
        return ;
    }
    int mid = ( p[id].ll + p[id].rr ) / 2 ;
    if ( num <= mid )
    update( 2*id , num , flag );
    else
    update( 2*id+1 , num , flag );

    p[id].lval = p[2*id].lval ;
    p[id].rval = p[2*id+1].rval ;
    
    //如果左子树的最右边的点和右子树的最左端的点是相连的,那么他们的父节点的左边相连的
    //点的个数要用左子树右边相连点的数加上右子树左边相连点个数。
    if( p[2*id].rval == ( p[2*id].rr - p[2*id].ll + 1))
    p[id].lval += p[2*id+1].lval ;
    //同上
    if( p[2*id+1].rval == ( p[2*id+1].rr - p[2*id+1].ll + 1 ))
    p[id].rval += p[2*id].rval ;
}

int query( int id , int num )
{
    if ( p[id].rval == ( p[id].rr - p[id].ll + 1 ))
    {
        return ( p[id].rr - p[id].ll + 1 );
    }
    int mid = ( p[id].ll + p[id].rr ) / 2 ;
    if ( num <= mid )
    {
        if ( p[2*id].rval >= p[2*id].rr - num +1 )
        return query( 2*id , num ) + p[2*id+1].lval ;
        else
        return query( 2*id , num );
    }
    else
    {
        //同上,如果父节点的左端相连的点不止包含在右子树中,还包含在左子树中,那么
        //加上左子树的右端的相连点的个数
        if( p[2*id+1].lval >= num - p[2*id+1].ll + 1 )
        return query( 2*id+1 , num ) + p[2*id].rval ;
        else
        return query( 2*id +1 , num );
    }
}

int main()
{
    int i , x ;
    char c ;
    scanf( "%d%d" , &n , &m );
    {
        fill( vis , vis + n + 1 , 1 );
        make_tree( 1 , 1 , n );
        //st.clear();
        while( m-- )
        {
            getchar();
            scanf( "%c" , &c );
            if ( c == 'D' )
            {
                scanf( "%d" , &x );
                st.push( x );
                //st.pop();
                update( 1 , x , 0 );
            }
            else if ( c == 'R' )
            {
                x = st.top();
                st.pop();
                update( 1 , x , 1 );
            }
            else
            {
                scanf( "%d" , &x );
                //查询时,如果该点已经被破坏掉,那么直接输出0
                if ( !vis[x] )
                printf ( "0\n" );
                else
                printf ( "%d\n" , query( 1 , x ));
            }
        }
    }
    return 0 ;
}
posted @ 2012-08-06 15:40  Misty_1  阅读(151)  评论(0编辑  收藏  举报