HDU 1540 HDOJ 1540 Tunnel Warfare ACM 1540 IN HDU

MiYu原创, 转帖请注明 : 转载自 ______________白白の屋    

 

题目地址:

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

题目描述:

Tunnel Warfare

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1009    Accepted Submission(s): 334


Problem Description
During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every village was directly connected with two neighboring ones.

Frequently the invaders launched attack on some of the villages and destroyed the parts of tunnels in them. The Eighth Route Army commanders requested the latest connection state of the tunnels and villages. If some villages are severely isolated, restoration of connection must be done immediately!
 

Input
The first line of the input contains two positive integers n and m (n, m ≤ 50,000) indicating the number of villages and events. Each of the next m lines describes an event.

There are three different events described in different format shown below:

D x: The x-th village was destroyed.

Q x: The Army commands requested the number of villages that x-th village was directly or indirectly connected with including itself.

R: The village destroyed last was rebuilt.
 

Output
Output the answer to each of the Army commanders’ request in order on a separate line.
 

Sample Input
   
     
7 9 D 3 D 6 D 5 Q 4 Q 5 R Q 4 R Q 4
 

Sample Output
   
     
1 0 2 4
 

 题目分析:

题目有三种操作 :

D:  摧毁村庄

Q: 查询相连的村庄

R: 修复上次被摧毁的村庄

这个题目的关键部分就是 对线段的修改部分, 也是最难的部分, 这部分理解了, 这个题目就基本会了.

  在结构体里面, 需要保存 3个量, lVal : 从线段左端点能够向右延伸的最大长度,

     rVal:从线段右端点能够向左延伸的最大长度,

    mVal:当前线段的最大连续长度

         seg[rt].mVal = max ( seg[LL].rVal + seg[RR].lVal, max ( seg[LL].mVal, seg[RR].mVal ) ); //当前节点的最大连续长度 

         seg[rt].lVal = seg[LL].lVal + ( seg[LL].cov() ? seg[RR].lVal : 0 );   //当前节点的左端点能够向右延伸的最大长度 

         seg[rt].rVal = seg[RR].rVal + ( seg[RR].cov() ? seg[LL].rVal : 0 );   //当前节点的右端点能够向左延伸的最大长度  

查询的时候也要注意几种 情况 :  1 :  就是当前整个线段

      2 :  横跨 左右子树

      3 :  只在 左 或 右 子树

详细请看代码注释. 

代码如下 : 

代码
/*
Mail to   : [email protected]
Link      :  http://www.cnblogs.com/MiYu   ||  http://www.cppblog.com/MiYu
Author By : MiYu
Test      : 1
Complier  : g++ mingw32-3.4.2
Program   : 1540
Doc Name  : Tunnel Warfare
*/
// #pragma warning( disable:4789 )
#include  < iostream >
#include  < fstream >
#include  < sstream >
#include  < algorithm >
#include  < string >
#include  < set >
#include  < map >
#include  < utility >
#include  < queue >
#include  < stack >
#include  < list >
#include  < vector >
#include  < cstdio >
#include  < cstdlib >
#include  < cstring >
#include  < cmath >
#include  < ctime >
using   namespace  std;
inline  int  max (  int   & a,  int   & b ) {
       
return  a  >  b  ?  a : b;       
}
struct  segTree {
       
int  left, right, lVal, rVal, mVal;  // lVal: 从线段左端点能够向右延伸的最大长度
                                          
// rVal: 从线段右端点能够向左延伸的最大长度 
                                          
// mVal: 当前线段的最大连续长度 
        int  mid () {  return  (left  +  right) >> 1 ;}  
       
int  dis () {  return  right - left + 1 ; }   //  线段的长度 
        void  prs ( int  flag) { lVal  =  rVal  =  mVal  =  flag  ?   0  : dis(); }    // 按flag标记处理线段 
        bool  cov () {  return  mVal  ==  dis(); }    //  当前线段是否被覆盖 , 即 这条线段上的点没有任何一点被破坏 
}seg[ 160000 ];
inline  void  creat (  int  left,  int  right,  int  rt  =   1  ) {
     
int  LL  =  rt  <<   1 , RR  =  rt  <<   1   |   1
     seg[rt].left  =  left;
     seg[rt].right  =  right;
     seg[rt].prs ( 0 );
     
if  ( left  ==  right )  return
     
int  mid  =  seg[rt].mid();      
     creat ( left, mid, LL );
     creat ( mid  +   1 , right, RR );     
}
inline  void  modify (  int  pos,  int  flag,  int  rt  =   1  ) {
     
int  LL  =  rt  <<   1 , RR  =  rt  <<   1   |   1
     
if  ( seg[rt].left  ==  seg[rt].right ) {
          seg[rt].prs ( flag );  return ;      
     } 
     
int  mid  =  seg[rt].mid();
     
if  ( pos  <=  mid ) modify ( pos, flag, LL );
     
else  modify ( pos, flag, RR );
     
//  经典部分: 
     seg[rt].mVal  =  max ( seg[LL].rVal  +  seg[RR].lVal, max ( seg[LL].mVal, seg[RR].mVal ) );  // 当前节点的最大连续长度 
     seg[rt].lVal  =  seg[LL].lVal  +  ( seg[LL].cov()  ?  seg[RR].lVal :  0  );    // 当前节点的左端点能够向右延伸的最大长度 
     seg[rt].rVal  =  seg[RR].rVal  +  ( seg[RR].cov()  ?  seg[LL].rVal :  0  );    // 当前节点的右端点能够向左延伸的最大长度 
}
inline  int  query (  int  pos,  int  rt  =   1  ) {
    
if  ( seg[rt].cov()  ||  seg[rt].mVal  ==   0   ||  seg[rt].left  ==  seg[rt].right )
        
return  seg[rt].mVal;
    
int  LL  =  rt  <<   1 , RR  =  rt  <<   1   |   1 , mid  =  seg[rt].mid();        
    
if  ( pos  <=  mid ) {
         
if  ( pos  >  mid  -  seg[LL].rVal )   //  查询节点在左孩子节点所处的位置 
              return  seg[LL].rVal  +  query ( mid + 1 , RR );  //  如果在线段的右端, 则还需要查询右孩子节点的左端 
          else   return  query ( pos, LL );     // 左端只需查询左端 
    }  else  {
         
if  ( pos  <=  mid  +  seg[RR].lVal )   //  同上 
              return  seg[RR].lVal  +  query ( mid, LL );
         
else   return  query ( pos, RR );   
    }

inline  int  _getint( int   & n){   // 输入加速 
  char  c; for (c = getchar(); ! isdigit(c);c = getchar()); for (;isdigit(c);c = getchar())n = n * 10 + c - ' 0 ' ; return  n;
}
deque  < int >  st;  //  stack 没有clear() 杯具了 
int  main ()
{
    
int  N, M;
    
char  ask[ 3 ];
    
while  ( scanf (  " %d%d " & N,  & M )  ==   2  ) {
           creat (  1 , N );
           st.clear();
           
while  ( M  --  ) {
                  scanf (  " %s " ,ask ); N  =   0 ;
                  
switch  ( ask[ 0 ] ) {
                         
case   ' D ' :   _getint (N);
                                     modify ( N,  1  );
                                     st.push_back ( N );
                                     
break ;
                         
case   ' Q ' :   _getint (N);          
                                     printf (  " %d\n " ,query ( N ) );        
                                     
break ;
                         
case   ' R ' :    if  ( st.empty() )  break ;
                                     modify ( st.back(),  0  );
                                     st.pop_back();
                  }
           }
    }
    
return   0 ;
}

 

 

你可能感兴趣的:(ACM)