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 ; }