[SDOI2011]消耗战
Posted chy-2003
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SDOI2011]消耗战相关的知识,希望对你有一定的参考价值。
问题分析
显然是虚树题。由于\(\sum k\leqslant 500000\),所以直接套个虚树就好了。时间经过实践是可以的。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int Maxn = 250010;
const long long INF = 125000000010;
const int MaxLog = 20;
struct edge
int To, Next;
long long c;
edge() : To( 0 ), Next( 0 ), c( 0 )
edge( int _To, int _Next, long long _c ) : To( _To ), Next( _Next ), c( _c )
;
edge Edge[ Maxn << 1 ];
int Start[ Maxn ], UsedEdge;
inline void AddEdge( int x, int y, long long z )
Edge[ ++UsedEdge ] = edge( y, Start[ x ], z );
Start[ x ] = UsedEdge;
return;
int n, Dfn[ Maxn ], Deep[ Maxn ], Time;
struct step
int To;
long long Min;
step() : To( 0 ), Min( INF )
step( int _To, long long _Min ) : To( _To ), Min( _Min )
;
step Step[ Maxn ][ MaxLog ];
int m, k, H[ Maxn ];
void Build( int u, int Fa, long long c )
Dfn[ u ] = ++Time;
Deep[ u ] = Deep[ Fa ] + 1;
Step[ u ][ 0 ] = step( Fa, c );
for( int i = 1; i < MaxLog; ++i )
Step[ u ][ i ] = step( Step[ Step[ u ][ i - 1 ].To ][ i - 1 ].To,
min( Step[ u ][ i - 1 ].Min, Step[ Step[ u ][ i - 1 ].To ][ i - 1 ].Min ) );
for( int t = Start[ u ]; t; t = Edge[ t ].Next )
int v = Edge[ t ].To;
if( v == Fa ) continue;
Build( v, u, Edge[ t ].c );
return;
inline bool Cmp( int x, int y )
return Dfn[ x ] < Dfn[ y ];
edge Edge2[ Maxn << 1 ];
int Start2[ Maxn ], UsedEdge2, Flag[ Maxn ], IsFlag[ Maxn ], Emmm;
int Stack[ Maxn ];
long long GetCost( int x, int y );
inline void AddEdge_2( int x, int y, long long z, int flag )
if( Flag[ x ] != flag )
Start2[ x ] = 0;
Flag[ x ] = flag;
Edge2[ ++UsedEdge2 ] = edge( y, Start2[ x ], z );
Start2[ x ] = UsedEdge2;
return;
inline void AddEdge2( int x, int y, int flag )
long long z = GetCost( x, y );
AddEdge_2( x, y, z, flag );
AddEdge_2( y, x, z, flag );
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[ Step[ x ][ i ].To ] >= Deep[ y ] )
x = Step[ x ][ i ].To;
if( x == y ) return x;
for( int i = MaxLog - 1; i >= 0; --i )
if( Step[ x ][ i ].To != Step[ y ][ i ].To )
x = Step[ x ][ i ].To;
y = Step[ y ][ i ].To;
return Step[ x ][ 0 ].To;
long long GetCost( int x, int y )
if( Deep[ x ] < Deep[ y ] ) swap( x, y );
long long Ans = INF;
for( int i = MaxLog - 1; i >= 0; --i )
if( Deep[ Step[ x ][ i ].To ] >= Deep[ y ] )
Ans = min( Ans, Step[ x ][ i ].Min );
x = Step[ x ][ i ].To;
return Ans;
long long Dp( int u, int Fa )
long long Ans = 0;
int Cnt = 0;
for( int t = Start2[ u ]; t; t = Edge2[ t ].Next )
int v = Edge2[ t ].To;
if( v == Fa ) continue;
++Cnt;
if( IsFlag[ v ] == Emmm )
Ans += Edge2[ t ].c;
else
Ans += min( Edge2[ t ].c, Dp( v, u ) );
if( Cnt ) return Ans; else return INF;
int main()
scanf( "%d", &n );
for( int i = 1; i < n; ++i )
int x, y; long long z;
scanf( "%d%d%lld", &x, &y, &z );
AddEdge( x, y, z );
AddEdge( y, x, z );
Build( 1, 1, INF );
scanf( "%d", &m );
for( int i = 1; i <= m; ++i )
scanf( "%d", &k );
for( int j = 1; j <= k; ++j ) scanf( "%d", &H[ j ] );
sort( H + 1, H + k + 1, Cmp );
for( int j = 1; j <= k; ++j ) IsFlag[ H[ j ] ] = i;
Emmm = i;
UsedEdge2 = 0;
Stack[ 0 ] = 1; Stack[ 1 ] = 1;
for( int j = 1; j <= k; ++j )
int Lca = GetLca( Stack[ Stack[ 0 ] ], H[ j ] );
if( Deep[ Lca ] == Deep[ Stack[ Stack[ 0 ] ] ] )
Stack[ ++Stack[ 0 ] ] = H[ j ];
else
while( Deep[ Lca ] < Deep[ Stack[ Stack[ 0 ] - 1 ] ] )
AddEdge2( Stack[ Stack[ 0 ] ], Stack[ Stack[ 0 ] - 1 ], i );
--Stack[ 0 ];
if( Deep[ Lca ] == Deep[ Stack[ Stack[ 0 ] - 1 ] ] )
AddEdge2( Stack[ Stack[ 0 ] ], Stack[ Stack[ 0 ] - 1 ], i );
--Stack[ 0 ];
Stack[ ++Stack[ 0 ] ] = H[ j ];
else
AddEdge2( Stack[ Stack[ 0 ] ], Lca, i );
--Stack[ 0 ];
Stack[ ++Stack[ 0 ] ] = Lca;
Stack[ ++Stack[ 0 ] ] = H[ j ];
while( Stack[ 0 ] >= 2 )
AddEdge2( Stack[ Stack[ 0 ] ], Stack[ Stack[ 0 ] - 1 ], i );
--Stack[ 0 ];
printf( "%lld\n", Dp( 1, 0 ) );
return 0;
以上是关于[SDOI2011]消耗战的主要内容,如果未能解决你的问题,请参考以下文章