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\n" ); else printf( "%d\n", Ans );
}
return 0;
}