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