P4246 [SHOI2008]堵塞的交通

题意简述

维护一个 \(2*n\) 的网格图的动态连通性

思路

既然是动态连通性,那么我们直接离线线段树分治+可撤销并查集

上面的做法太暴力了,我们考虑分析一些性质

注意到联通的信息是可以合并的,可以考虑使用线段树维护

一个想法是维护区间 左上/左下 到 右上/右下 的连通性

但这样忽略了一种情况:

(1,1) - (1,2)   (1,3) - (1,4)
  |                       |
(2,1) - (2,2) - (2,3) - (2,4)

也就是说,我们可以通过询问区间 左边/右边 部分实现行的改变

那么再维护两个信息 \(l,r\) 表示区间 左上左下 , 右上右下 的连通性

合并区间和查询时枚举中间点即可

#include <cstdio>
#include <iostream>
using namespace std;

const int MAXN = 1e5;
int n , v[ MAXN + 5 ] , r[ 2 ][ MAXN + 5 ];

struct node { bool l , r; bool chk[ 2 ][ 2 ]; };
struct Segment_Tree {
    node tr[ 4 * MAXN + 5 ];
    #define ls x << 1
    #define rs x << 1 | 1
    #define mid ( l + r >> 1 )

    node Merge( node p , node q , int md ) {
        node S = {};
        for( int i = 0 ; i <= 1 ; i ++ )
            for( int j = 0 ; j <= 1 ; j ++ )
                for( int k = 0 ; k <= 1 ; k ++ )
                    S.chk[ i ][ j ] |= p.chk[ i ][ k ] & r[ k ][ md ] & q.chk[ k ][ j ];
        S.l = p.l | ( p.chk[ 0 ][ 0 ] && p.chk[ 1 ][ 1 ] && r[ 0 ][ md ] & r[ 1 ][ md ] & q.l );
        S.r = q.r | ( q.chk[ 0 ][ 0 ] && q.chk[ 1 ][ 1 ] && r[ 0 ][ md ] & r[ 1 ][ md ] & p.r );
        return S;
    }
    void Build( int x , int l = 1 , int r = n ) {
        if( l == r ) { tr[ x ].chk[ 0 ][ 0 ] = tr[ x ].chk[ 1 ][ 1 ] = 1; return; }
        Build( ls , l , mid ); Build( rs , mid + 1 , r );
    }
    void Update( int x , int pos , int l = 1 , int r = n ) {
        if( pos < l || pos > r ) return;
        if( l == r ) { tr[ x ].chk[ 0 ][ 1 ] = tr[ x ].chk[ 1 ][ 0 ] = tr[ x ].l = tr[ x ].r = v[ l ]; return; }
        Update( ls , pos , l , mid ); Update( rs , pos , mid + 1 , r );
        tr[ x ] = Merge( tr[ ls ] , tr[ rs ] , mid );
    }
    node Query( int x , int ql , int qr , int l = 1 , int r = n ) {
        if( ql <= l && r <= qr ) return tr[ x ];
        if( qr <= mid ) return Query( ls , ql , qr , l , mid );
        if( ql > mid ) return Query( rs , ql , qr , mid + 1 , r );
        return Merge( Query( ls , ql , qr , l , mid ) , Query( rs , ql , qr , mid + 1 , r ) , mid );
    }
}Tr;

char s[ 10 ];
int main( ) {
    scanf("%d",&n);
    Tr.Build( 1 );
    for( int r1 , c1 , r2 , c2 ; scanf("%s", s ) && s[ 0 ] != 'E' ; ) {
        scanf("%d %d %d %d",&r1,&c1,&r2,&c2); r1 -- , r2 --;
        if( s[ 0 ] == 'O' ) {
            if( r1 == r2 ) { if( c1 > c2 ) swap( c1 , c2 ); r[ r1 ][ c1 ] = 1; }
            else v[ c1 ] = 1; 
            Tr.Update( 1 , c1 );
        }
        if( s[ 0 ] == 'C' ) {
            if( r1 == r2 ) { if( c1 > c2 ) swap( c1 , c2 ); r[ r1 ][ c1 ] = 0; }
            else v[ c1 ] = 0; 
            Tr.Update( 1 , c1 );
        }
        if( s[ 0 ] == 'A' ) {
            bool ans = 0;
            if( c1 > c2 ) swap( c1 , c2 ) , swap( r1 , r2 );
            node S = Tr.Query( 1 , c1 , c2 ) , L = Tr.Query( 1 , 1 , c1 ) , R = Tr.Query( 1 , c2 , n );
            ans |= S.chk[ r1 ][ r2 ];
            ans |= S.chk[ r1 ][ !r2 ] & R.l;
            ans |= L.r & S.chk[ !r1 ][ r2 ];
            ans |= L.r & S.chk[ !r1 ][ !r2 ] & R.l;
            puts( ans ? "Y" : "N" ); 
        }
    }
    return 0;
}
posted @ 2022-03-27 22:14  chihik  阅读(14)  评论(0编辑  收藏  举报