BZOJ-1095: [ZJOI2007]Hide 捉迷藏(括号序列+线段树)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1095

这道题可以用动态树分治水过去,但是代码量相当大,于是乎我偷懒用了括号序列的写法,好不容易A掉了额。(神奇的传送门:http://www.shuizilong.com/house/archives/bzoj-1095-zjoi2007hide-%E6%8D%89%E8%BF%B7%E8%97%8F/)

代码:

#include 

#include 

#include 

#include 

#include 

 

using namespace std ;

 

#define AddEdge( s , t ) Add( s , t ),Add( t , s )

#define Add( s , t ) E[ s ].push_back( t )

 

#define left( t ) ( t <<1)

#define right( t ) (left( t )^1)

 

#define L( t ) Left[ t ]

#define R( t ) Right[ t ]

#define LP( t ) left_push[ t ]

#define RP( t ) right_push[ t ]

#define LM( t ) left_minus[ t ]

#define RM( t ) right_minus[ t ]

#define D( t ) Dist[ t ]

#define A( t ) la[ t ]

#define B( t ) rb[ t ]

 

#define rep( i , x ) for(int i =0; i ++< x ;)

#define travel( x ) for( vector :: iterator p = E[ x ].begin(  ); p != E[ x ].end(  );++ p )

 

const int maxn =101000;

const int inf =1000000000;

const int maxv = maxn <<3;

 

vector  E[ maxn ];

 

int n , m , in[ maxn ], out[ maxn ], dfn[ maxn <<1], num[ maxn <<1], Index =0;

bool col[ maxn <<1];

 

void dfs(int v ,int u ){

    num[ in[ v ]=++ Index ]=0;

    travel( v )if(*p != u )dfs(*p , v );

    num[ out[ v ]=++ Index ]=1;

}

 

int left_push[ maxv ], right_push[ maxv ], left_minus[ maxv ], right_minus[ maxv ];

int Left[ maxv ], Right[ maxv ], Dist[ maxv ], la[ maxv ], rb[ maxv ];

 

void update(int t ){

    if(L( t )A(right( t ))){

            A( t )=A(left( t ));

            B( t )=B(right( t ))+B(left( t ))-A(right( t ));

        }else{

            A( t )=A(left( t ))+A(right( t ))-B(left( t ));

            B( t )=B(right( t ));

        }

        LP( t )=max(LP(left( t )),max(A(left( t ))-B(left( t ))+LP(right( t )),A(left( t ))+B(left( t ))+LM(right( t ))));

        LM( t )=max(LM(left( t )),B(left( t ))-A(left( t ))+LM(right( t )));

        RP( t )=max(RP(right( t )),max(A(right( t ))+B(right( t ))+RM(left( t )),B(right( t ))-A(right( t ))+RP(left( t ))));

        RM( t )=max(RM(right( t )),A(right( t ))-B(right( t ))+RM(left( t )));

        D( t )=max(max(D(left( t )),D(right( t ))),max(RM(left( t ))+LP(right( t )),RP(left( t ))+LM(right( t ))));

    }

}

 

void build(int l ,int r ,int t ){

    L( t )= l ,R( t )= r ;

    if( l == r ){

        A( t )= num[ l ]==1?1:0;

        B( t )= num[ l ]==0?1:0;

        if(! col[ r +1]){

            LP( t )=A( t )+B( t );

            LM( t )=B( t )-A( t );

        }else{

            LP( t )=LM( t )=- inf ;

        }

        if(! col[ l -1]){

            RP( t )=A( t )+B( t );

            RM( t )=A( t )-B( t );

        }else{

            RP( t )=RM( t )=- inf ;

        }

        if(! col[ l -1]&&! col[ r +1]){

            D( t )=1;

        }else D( t )=- inf ;

        return;

    }

    int mid =( l + r )>>1;

    build( l , mid ,left( t )),build( mid +1, r ,right( t ));

    update( t );

}

 

void change(int x ,int t ){

    if(L( t )==R( t )){

        if(! col[ x +1]){

            LP( t )=A( t )+B( t );

            LM( t )=B( t )-A( t );

        }else{

            LP( t )=LM( t )=- inf ;

        }

        if(! col[ x -1]){

            RP( t )=A( t )+B( t );

            RM( t )=A( t )-B( t );

        }else{

            RP( t )=RM( t )=- inf ;

        }

        if(! col[ x -1]&&! col[ x +1]){

            D( t )=1;

        }else D( t )=- inf ;

        return;

    }

    int mid =(L( t )+R( t ))>>1;

    change( x , x <= mid ?left( t ):right( t ));

    update( t );

}

 

void Change(int v ){

    col[ in[ v ]]^=true;

    if( in[ v ]-1)change( in[ v ]-1,1);

    if( in[ v ]<( n <<1))change( in[ v ]+1,1);

    col[ out[ v ]]^=true;

    if( out[ v ]-1)change( out[ v ]-1,1);

    if( out[ v ]<( n <<1))change( out[ v ]+1,1);

}

 

int main(  ){

    scanf("%d",&n );

    rep( i , n -1){

        int s , t ;scanf("%d%d",&s ,&t );

        AddEdge( s , t );

    }

    dfs(1,0);

    memset( col ,false,sizeof( col ));

    col[0]= col[( n <<1)+1]=true;

    build(1, n <<1,1);

    scanf("%d",&m );

    while( m --){

        int ch ;for( ch =getchar(  ); ch !='G'&& ch !='C'; ch =getchar(  ));

        if( ch =='C'){

            int v ;scanf("%d",&v );

            Change( v );

        }else printf("%d\n",D(1));

    }

    return 0;

}

你可能感兴趣的:(BZOJ-1095: [ZJOI2007]Hide 捉迷藏(括号序列+线段树))