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;
}

posted @ 2019-09-29 16:40  chy_2003  阅读(115)  评论(0编辑  收藏  举报