P3703 [SDOI2017]树点涂色

众所周知,\(\text{access(x)}\)\(rt \to x\) 这条实链在一个 \(splay\) 中。也就是说, \(splay\) 所维护的链中的点同色。

那么到点 \(x\) 到根路径的权值便是经过虚边的数量 \(+1\),不妨记为 \(dis_x\)

  • 对于修改操作,每次爬虚边时都会将两条边虚实反转,这两条边所连向的子树内的点 \(dis\) 分别会 \(+1/-1\)。求出 \(\text{dfs}\) 序后用线段树维护即可。注意在深度最小点上修改。

  • 对于询问2,两点 \(x,y\) 之间路径的权值便为: \(dis_x+dis_y-2dis_{lca(x,y)}+1\)

  • 对于询问3,线段树查询 \(x\) 子树 \(\max \{ dis \}\)即可。

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

const int MAXN = 1e5 , LOG = 18;

int n , m;
vector< int > Graph[ MAXN + 5 ];

int tim , dfn[ MAXN + 5 ] , rk[ MAXN + 5 ] , siz[ MAXN + 5 ];
int dep[ MAXN + 5 ] , Anc[ MAXN + 5 ][ LOG + 1 ];
void dfs( int u , int fa ) {
    dep[ u ] = dep[ fa ] + 1; Anc[ u ][ 0 ] = fa; dfn[ u ] = ++ tim; rk[ tim ] = u; siz[ u ] = 1;
    for( int i = 1 ; i <= LOG ; i ++ ) Anc[ u ][ i ] = Anc[ Anc[ u ][ i - 1 ] ][ i - 1 ];
    for( int i = 0 ; i < Graph[ u ].size() ; i ++ ) {
        int v = Graph[ u ][ i ];
        if( v == fa ) continue;
        dfs( v , u ); siz[ u ] += siz[ v ];
    }
}
int lca( int u , int v ) {
    if( dep[ u ] < dep[ v ] ) swap( u , v );
    for( int i = LOG ; i >= 0 ; i -- ) if( dep[ Anc[ u ][ i ] ] >= dep[ v ] ) u = Anc[ u ][ i ];
    if( u == v ) return u;
    for( int i = LOG ; i >= 0 ; i -- ) if( Anc[ u ][ i ] != Anc[ v ][ i ] ) u = Anc[ u ][ i ] , v = Anc[ v ][ i ];
    return Anc[ u ][ 0 ];
}

struct node1 {
    int l , r;
    int Max , add;
};
struct Segment_Tree {
    node1 Tree[ 4 * MAXN + 5 ];
    #define ls x << 1
    #define rs x << 1 | 1

    void Pushup( int x ) { Tree[ x ].Max = max( Tree[ ls ].Max , Tree[ rs ].Max ); }
    void Add( int x , int k ) { Tree[ x ].add += k; Tree[ x ].Max += k; }
    void Pushdown( int x ) { if( Tree[ x ].add ) Add( ls , Tree[ x ].add ) , Add( rs , Tree[ x ].add ) , Tree[ x ].add = 0; }
    void Build( int x , int l , int r ) {
        Tree[ x ].l = l , Tree[ x ].r = r;
        if( l == r ) { Tree[ x ].Max = dep[ rk[ l ] ]; return; }
        int Mid = ( l + r ) >> 1;
        Build( ls , l , Mid ); Build( rs , Mid + 1 , r );
        Pushup( x );
    }
    void Update( int x , int l , int r , int k ) {
        if( r < Tree[ x ].l || Tree[ x ].r < l ) return;
        if( l <= Tree[ x ].l && Tree[ x ].r <= r ) return Add( x , k );
        Pushdown( x );
        Update( ls , l , r , k ); Update( rs , l , r , k );
        Pushup( x );
    }
    int Query_max( int x , int l , int r ) {
        if( r < Tree[ x ].l || Tree[ x ].r < l ) return 0;
        if( l <= Tree[ x ].l && Tree[ x ].r <= r ) return Tree[ x ].Max;
        Pushdown( x );
        return max( Query_max( ls , l , r ) , Query_max( rs , l , r ) );
    }
}STree;

struct node2 {
    int ch[ 2 ] , fa;
};
struct LinkCutTree {
    node2 Tree[ MAXN + 5 ];
    #define ls( x ) Tree[ x ].ch[ 0 ]
    #define rs( x ) Tree[ x ].ch[ 1 ]

    bool isrt( int x ) {
        return ls( Tree[ x ].fa ) != x && rs( Tree[ x ].fa ) != x;
    }
    bool chk( int x ) { return rs( Tree[ x ].fa ) == x; }
    void Rotate( int x ) {
        int y = Tree[ x ].fa , z = Tree[ y ].fa , p = chk( x ) , a = Tree[ x ].ch[ !p ];
        if( !isrt( y ) ) Tree[ z ].ch[ chk( y ) ] = x; Tree[ x ].fa = z;
        Tree[ x ].ch[ !p ] = y; Tree[ y ].fa = x;
        Tree[ y ].ch[ p ] = a; if( a ) Tree[ a ].fa = y;
    }
    void Splay( int x ) {
        while( !isrt( x ) ) {
            int y = Tree[ x ].fa , z = Tree[ y ].fa;
            if( !isrt( y ) ) Rotate( chk( x ) == chk( y ) ? y : x );
            Rotate( x );
        }
    }

    int Findroot( int x ) {
        for( ; ls( x ) ; x = ls( x ) );
        return x;
    }
    void Access( int x ) {
        for( int y = 0 , p ; x ; y = x , x = Tree[ x ].fa ) {
            Splay( x );
            if( p = Findroot( rs( x ) ) ) STree.Update( 1 , dfn[ p ] , dfn[ p ] + siz[ p ] - 1 , 1 );
            if( p = Findroot( rs( x ) = y ) ) STree.Update( 1 , dfn[ p ] , dfn[ p ] + siz[ p ] - 1 , -1 );
        }
    }
}LCT;

int main( ) {
    scanf("%d %d",&n,&m);
    for( int i = 1 , u , v ; i < n ; i ++ ) {
        scanf("%d %d",&u,&v);
        Graph[ u ].push_back( v );
        Graph[ v ].push_back( u );
    }
    dfs( 1 , 0 ); for( int i = 1 ; i <= n ; i ++ ) LCT.Tree[ i ].fa = Anc[ i ][ 0 ];
    STree.Build( 1 , 1 , n );

    for( int i = 1 , op , u , v ; i <= m ; i ++ ) {
        scanf("%d",&op);
        if( op == 1 ) {
            scanf("%d",&u);
            LCT.Access( u );
        }
        if( op == 2 ) {
            scanf("%d %d",&u,&v);
            int w = lca( u , v );
            printf("%d\n", STree.Query_max( 1 , dfn[ u ] , dfn[ u ] ) + STree.Query_max( 1 , dfn[ v ] , dfn[ v ] ) - 2 * STree.Query_max( 1 , dfn[ w ] , dfn[ w ] ) + 1 );
        }
        if( op == 3 ) {
            scanf("%d",&u);
            printf("%d\n", STree.Query_max( 1 , dfn[ u ] , dfn[ u ] + siz[ u ] - 1 ) );
        }
    }
    return 0;
}
posted @ 2021-04-08 21:35  chihik  阅读(54)  评论(0编辑  收藏  举报