0w1

CFR 342 E. Xenia and Tree ( LCA + Square Decompostion )

Problem - E - Codeforces
如果對於一個詢問,對所有塗色點取最小距離,複雜度為O( N ),如果對於一個添加所有點的答案,複雜度為O( N )。又只要開始的時候將所有始點押入 queue,囤積複數個始點再更新所有點的答案的複雜度依然為O( N ),可以考慮平方分割。對於一個新的添加,不馬上利用它更新答案而是押入一個集合,令集合最大容量為 B,當集合大小超過 B,集合裡的所有點押入 queue立刻更新。對於一個詢問,取已更新的答案和對未更新的點一一取最小距離判斷。複雜度為 O( N * M / B + B * lg( N ) * M )。

#include <bits/stdc++.h>
using namespace std;

typedef vector< int > vi;
typedef vector< vi > vvi;

const int BSIZE = 77;

void fillTable( int u, int fa, int lv, const vvi &G, vi &depth, vvi &par ){
    depth[ u ] = lv;
    for( int v : G[ u ] ){
        if( v == fa ) continue;
        fillTable( v, u, lv + 1, G, depth, par );
        par[ 0 ][ v ] = u;
    }
}

int getLCA( int u, int v, const vi &depth, const vvi &par ){
    if( not ( depth[ u ] > depth[ v ] ) )
        swap( u, v );

    int diff = depth[ u ] - depth[ v ];
    for( int i = 19; diff; --i )
        if( diff >= 1 << i )
            u = par[ i ][ u ],
            diff -= 1 << i;

    if( u == v ) return u;

    for( int i = 19; par[ 0 ][ u ] != par[ 0 ][ v ]; --i )
        if( par[ i ][ u ] != par[ i ][ v ] )
            u = par[ i ][ u ],
            v = par[ i ][ v ];

    return par[ 0 ][ u ];
}

int getDis( int u, int v, const vi &depth, const vvi &par ){
    return depth[ u ] + depth[ v ] - 2 * depth[ getLCA( u, v, depth, par ) ];
}

void bfs( vi &dis, deque< int > que, const vvi &G ){
    while( !que.empty() ){
        int u = que.front();
        que.pop_front();
        for( int nu : G[ u ] )
            if( dis[ nu ] > dis[ u ] + 1 )
                dis[ nu ] = dis[ u ] + 1,
                que.push_back( nu );
    }
}

int main(){
    ios::sync_with_stdio( false );
    cin.tie( 0 );
    cout.tie( 0 );

    int N, M; cin >> N >> M;

    vvi G( N );
    for( int i = 0; i < N - 1; ++i ){
        int a, b; cin >> a >> b;
        --a, --b;
        G[ a ].push_back( b );
        G[ b ].push_back( a );
    }

    vi depth( N );
    vvi par( 20, vi( N ) );
    for( int i = 0; i < 20; ++i )
        fill( par[ i ].begin(), par[ i ].end(), -1 );
    fillTable( 0, -1, 0, G, depth, par );
    for( int i = 0; i + 1 < 20; ++i )
        for( int u = 0; u < N; ++u )
            if( par[ i ][ u ] != -1 )
                par[ i + 1 ][ u ] = par[ i ][ par[ i ][ u ] ];

    vi dis( N, 1e9 ); dis[ 0 ] = 0;
    bfs( dis, { 0 }, G );

    vi lazy_set;
    for( int i = 0; i < M; ++i ){
        int op, v; cin >> op >> v;
        --v;
        if( op == 1 ){
            lazy_set.push_back( v );
            if( lazy_set.size() > BSIZE ){
                deque< int > que;
                for( int u : lazy_set )
                    que.push_back( u ),
                    dis[ u ] = 0;
                lazy_set.clear();
                bfs( dis, que, G );
            }
        } else{
            int ans = dis[ v ];
            for( int u : lazy_set )
                ans = min( ans, getDis( u, v, depth, par ) );
            cout << ans << "\n";
        }
    }

    return 0;
}