现在的位置: 首页 > 综合 > 正文

HDU_1540 Tunnel Warfare 线段树

2014年02月21日 ⁄ 综合 ⁄ 共 2279字 ⁄ 字号 评论关闭

http://acm.hdu.edu.cn/showproblem.php?pid=1540

题意 :

有N座相互连接的桥,每座桥都只和其前面和后面的两座桥连接,现在有三种操作:

D i :表示将第i座桥破坏;

Q i:表示询问与第i座桥相互连接的桥的数目;

R : 表示修好最近一座被毁坏的桥 ;

思路:

线段树。首先对于D操作和R操作,很简单,我们只需要用线段树的单点更新就可以了,R操作可以用一个栈维护。比较麻烦的就是Q操作了,对于每次的Q操作,我们可以先求出i点左边的与之相连的点的个数,再求出其右边与之相连的点的个数,最后相加就可以了。而求其右边与之相连的点的个数的时候可以用一颗线段树来求, 线段树的每个节点记录三个信息:col表示该区间的颜色,-1:混合,0:毁坏,1 :完好 ; lnum :表示该区间左边与左端点相连的点的个数; rnum表示相应的右端点。
这样当我们每次询问的时候,对于一个区间(a,b)如果 b<=mid 那么就询问左孩子,如果 mid<a ,就去询问右孩子,如果两边都有的话,就先求出左孩子的(a , mid)中以a为端点的相连的长度,如果该长度等于mid-a+1,那么就要加上右孩子的左边的相连的长度。否则就只有(a,mid )中的长度了。

代码:

#include<stdio.h>
#include<string.h>
#include<stack>
using namespace std;
#define LL(a) ( (a)<<1 )
#define RR(a) ( (a)<<1|1 )
const int MAXN = 50010 ;

int col[MAXN<<2] ;
int lnum[MAXN<<2] , rnum[MAXN<<2] ;
int N , M ;
stack<int>  s;

void build(int l ,int r, int idx){
    col[idx] = 1 ;
    lnum[idx] = rnum[idx] = r-l+1 ;
    if( l == r )    return ;
    int mid = (l + r) >> 1  ;
    build( l , mid , LL(idx) ) ;
    build( mid+1 , r , RR(idx) ) ;
}

void up(int l ,int r, int idx){
    int mid = (l + r) >> 1 ;
    if( col[ LL(idx) ] == col[ RR(idx) ] )
        col[idx] = col[ LL(idx) ] ;
    else
        col[idx] = -1 ;
    lnum[idx] = lnum[ LL(idx) ] ;
    if( lnum[ LL(idx) ] == mid-l+1 )
        lnum[idx] += lnum[ RR(idx) ] ;
    rnum[idx] = rnum[ RR(idx) ] ;
    if( rnum[ RR(idx) ] == r - mid )
        rnum[idx] += rnum[ LL(idx) ] ;
}

void update(int l ,int r, int idx , int pos , int vv ){
    if( l == r ){
        col[idx] = vv ;
        if( vv == 0 ){
            lnum[idx] = rnum[idx] = 0 ;
        }
        else
            lnum[idx] = rnum[idx]  =1 ;
        return ;
    }
    int mid = (l + r) >> 1 ;
    if( pos <= mid )    update(l , mid , LL(idx) , pos , vv) ;
    else                update(mid+1 , r , RR(idx) , pos ,vv ) ;
    up(l, r ,idx);
}

int query(int l ,int r, int idx, int a , int b ){
    if(l==a && r==b){
        return lnum[idx] ;
    }
    int mid = (l + r) >> 1 ;
    if( b<=mid )    return query(l , mid , LL(idx) , a , b );
    else if( mid<a )    return query(mid+1 , r ,RR(idx) , a, b);
    else{
        int a1 = query(l , mid , LL(idx) , a, mid );
        int a2 = query(mid+1 , r , RR(idx) , mid+1 , b );
        if(a1 == mid-a+1){
            a1 += a2 ;
        }
        return a1 ;
    }
}

int query2(int l ,int r, int idx, int a, int b){
    if(a==l && b==r){
        return rnum[idx] ;
    }
    int mid = (l + r) >> 1 ;
    if( b<=mid )    return query2(l, mid , LL(idx) , a , b );
    else if( mid<a )    return query2(mid+1 , r, RR(idx) , a , b);
    else{
        int a1 = query2( l , mid , LL(idx) , a,  mid );
        int a2 = query2( mid+1 , r, RR(idx) , mid+1, b );
        if( a2 == b - mid )
            a2 += a1 ;
        return a2 ;
    }
}

int main(){
    char op[10] ;
    int a ;
    while( scanf("%d %d",&N,&M) == 2){
        build(1 , N ,1 );
        while( !s.empty() ) s.pop() ;
        for(int i=1;i<=M;i++){
            scanf("%s",op);
            if( op[0] == 'D' ){
                scanf("%d",&a);
                update(1 , N , 1 , a , 0 );
                s.push( a );
            }
            else if( op[0] == 'Q' ){
                scanf("%d",&a);
                int a1 = query(1 , N ,1 ,a , N );
                if(a-1>=1 && a1>0){
                    int a2 = query2(1 , N ,1 ,1 , a-1 );
                    a1 += a2 ;
                }
                printf("%d\n",a1);
            }
            else{
                a = s.top() ; s.pop() ;
                update(1 , N ,1 ,a , 1 );
            }
        }
    }
    return 0 ;
}

抱歉!评论已关闭.