CF613D Kingdom and its Cities

Posted chy-2003

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF613D Kingdom and its Cities相关的知识,希望对你有一定的参考价值。

题目链接

问题分析

首先看数据范围不难发现是虚树。

但是这个DP怎么写的我这么难受……

应该是不难的DP,(F[i][0])表示(i)不占领,(F[i][1])表示(i)占领,然后分类讨论……具体的见代码吧……

参考程序

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

const int Maxn = 100010;
const int INF = 1000010;
const int MaxLog = 20;
struct edge {
    int Next, To;
    edge() {}
    edge( int _To, int _Next ) : Next( _Next ), To( _To ) {}
};
struct graph {
    int Start[ Maxn ], Used;
    edge Edge[ Maxn << 1 ];
    int State, Flag[ Maxn ], Important[ Maxn ];
    graph() {
        memset( Flag, 255, sizeof( Flag ) );
        memset( Important, 255, sizeof( Important ) );
        Used = State = 0;
        return;
    }
    inline void Set( int _State ) {
        State = _State; Used = 0;
        return;
    }
    inline void SetImportant( int u ) {
        Important[ u ] = State;
        return;
    }
    inline bool IsImportant( int u ) {
        return Important[ u ] == State;
    }
    inline void AddDirectedEdge( int x, int y ) {
        if( Flag[ x ] != State ) {
            Flag[ x ] = State;
            Start[ x ] = 0;
        }
        Edge[ ++Used ] = edge( y, Start[ x ] );
        Start[ x ] = Used;
        return;
    }
    inline void AddUndirectedEdge( int x, int y ) {
        AddDirectedEdge( x, y );
        AddDirectedEdge( y, x );
        return;
    }
};
graph Prime, Now;
int n, q, k, A[ Maxn ];
int Deep[ Maxn ], D[ Maxn ][ MaxLog ], Dfn[ Maxn ], Time;

void Build( int u, int Fa ) {
    Dfn[ u ] = ++Time;
    Deep[ u ] = Deep[ Fa ] + 1;
    D[ u ][ 0 ] = Fa;
    for( int i = 1; i < MaxLog; ++i ) 
        D[ u ][ i ] = D[ D[ u ][ i - 1 ] ][ i - 1 ];
    for( int t = Prime.Start[ u ]; t; t = Prime.Edge[ t ].Next ) {
        int v = Prime.Edge[ t ].To;
        if( v == Fa ) continue;
        Build( v, u );
    }
    return;
}

int GetLca( int x, int y ) {
    if( Deep[ x ] < Deep[ y ] ) swap( x, y );
    for( int i = MaxLog - 1; i >= 0; --i ) 
        if( Deep[ D[ x ][ i ] ] >= Deep[ y ] )
            x = D[ x ][ i ];
    if( x == y ) return x;
    for( int i = MaxLog - 1; i >= 0; --i )
        if( D[ x ][ i ] != D[ y ][ i ] ) {
            x = D[ x ][ i ];
            y = D[ y ][ i ];
        }
    return D[ x ][ 0 ];
}

int Stack[ Maxn ];

bool Cmp( int x, int y ) {
    return Dfn[ x ] < Dfn[ y ];
}

int F[ Maxn ][ 2 ];

void Dp( int u, int Fa ) {
    for( int t = Now.Start[ u ]; t; t = Now.Edge[ t ].Next ) {
        int v = Now.Edge[ t ].To;
        if( v == Fa ) continue;
        Dp( v, u );
    }
    if( Now.IsImportant( u ) ) {
        F[ u ][ 0 ] = INF;
        F[ u ][ 1 ] = 0;
        for( int t = Now.Start[ u ]; t; t = Now.Edge[ t ].Next ) {
            int v = Now.Edge[ t ].To;
            if( v == Fa ) continue;
            if( Deep[ v ] - Deep[ u ] > 1 )
                F[ u ][ 1 ] += min( F[ v ][ 0 ], F[ v ][ 1 ] + 1 );
            else 
                F[ u ][ 1 ] += F[ v ][ 0 ];
        }
    } else {
        F[ u ][ 0 ] = 0;
        int Max = 0;
        for( int t = Now.Start[ u ]; t; t = Now.Edge[ t ].Next ) {
            int v = Now.Edge[ t ].To;
            if( v == Fa ) continue;
            if( Deep[ v ] - Deep[ u ] > 1 ) {
                F[ u ][ 0 ] += min( F[ v ][ 0 ], F[ v ][ 1 ] + 1 );
                Max = max( Max, min( F[ v ][ 0 ], F[ v ][ 1 ] + 1 ) - F[ v ][ 1 ] );
            } else {
                F[ u ][ 0 ] += F[ v ][ 0 ];
                Max = max( Max, F[ v ][ 0 ] - F[ v ][ 1 ] );
            }
        }
        F[ u ][ 1 ] = F[ u ][ 0 ] - Max;
        int T = 1;
        for( int t = Now.Start[ u ]; t; t = Now.Edge[ t ].Next ) {
            int v = Now.Edge[ t ].To;
            if( v == Fa ) continue;
            T += min( F[ v ][ 0 ], F[ v ][ 1 ] );
        }
        F[ u ][ 0 ] = min( F[ u ][ 0 ], T );
    }
    return;
}

int main() {
    Prime.Set( 0 );
    scanf( "%d", &n );
    for( int i = 1; i < n; ++i ) {
        int x, y;
        scanf( "%d%d", &x, &y );
        Prime.AddUndirectedEdge( x, y );
    }
    Build( 1, 0 );
    scanf( "%d", &q );
    for( int i = 1; i <= q; ++i ) {
        Now.Set( i );
        scanf( "%d", &k );
        for( int j = 1; j <= k; ++j ) scanf( "%d", &A[ j ] );
        for( int j = 1; j <= k; ++j ) Now.SetImportant( A[ j ] );
        sort( A + 1, A + k + 1, Cmp );
        Stack[ 0 ] = Stack[ 1 ] = 1;
        for( int j = 1; j <= k; ++j ) {
            if( j == 1 && A[ 1 ] == 1 ) continue;
            int Lca = GetLca( Stack[ Stack[ 0 ] ], A[ j ] );
            if( Deep[ Lca ] == Deep[ Stack[ Stack[ 0 ] ] ] )
                Stack[ ++Stack[ 0 ] ] = A[ j ];
            else {
                while( Deep[ Lca ] < Deep[ Stack[ Stack[ 0 ] - 1 ] ] ) {
                    Now.AddUndirectedEdge( Stack[ Stack[ 0 ] ], Stack[ Stack[ 0 ] - 1 ] );
                    --Stack[ 0 ];
                }
                if( Deep[ Lca ] == Deep[ Stack[ Stack[ 0 ] - 1 ] ] ) {
                    Now.AddUndirectedEdge( Stack[ Stack[ 0 ] ], Stack[ Stack[ 0 ] - 1 ] );
                    --Stack[ 0 ];
                    Stack[ ++Stack[ 0 ] ] = A[ j ];
                } else {
                    Now.AddUndirectedEdge( Stack[ Stack[ 0 ] ], Lca );
                    --Stack[ 0 ];
                    Stack[ ++Stack[ 0 ] ] = Lca;
                    Stack[ ++Stack[ 0 ] ] = A[ j ];
                }
            }
        }
        while( Stack[ 0 ] > 1 ) {
            Now.AddUndirectedEdge( Stack[ Stack[ 0 ] ], Stack[ Stack[ 0 ] - 1 ] );
            --Stack[ 0 ];
        }
        Dp( 1, 0 );
        int Ans = min( F[ 1 ][ 0 ], F[ 1 ][ 1 ] );
        if( Ans > n ) printf( "-1
" ); else printf( "%d
", Ans );
    }
    return 0;
}

以上是关于CF613D Kingdom and its Cities的主要内容,如果未能解决你的问题,请参考以下文章

CF613D Kingdom and its Cities

CF613D Kingdom and its Cities 虚树

题解 CF613D Kingdom and its Cities

codeforces 613D:Kingdom and its Cities

CodeForces - 613D:Kingdom and its Cities(虚树+DP)

CF613DKingdom and its Cities 虚树+树形DP