【BZOJ】2286: [Sdoi2011消耗战【虚树DP】

传送门:【BZOJ】2286: [Sdoi2011消耗战


my code:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std ;

typedef long long LL ;

#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clrs( a , x , sizes ) memset ( a , x , sizeof ( a[0] ) * ( sizes + 1 ) )
#define clr( a , x ) memset ( a , x , sizeof a )

const int MAXN = 250005 ;
const int MAXE = 500005 ;
const int LOG = 20 ;
const int INF = 0x3f3f3f3f ;
const LL oo = 1e18 ;

struct Edge {
	int v , c , n ;
	Edge () {}
	Edge ( int v , int c , int n ) : v ( v ) , c ( c ) , n ( n ) {}
} ;

Edge preE[MAXE] ;
Edge E[MAXE] ;
int preH[MAXN] , precntE ;
int H[MAXN] , cntE ;
int vis[MAXN] , Time ;
int minv[MAXN][LOG] ;
int S[MAXN] , top ;
int f[MAXN][LOG] ;
int tree[MAXN] ;
int idx[MAXN] ;
int dfs_clock ;
int dep[MAXN] ;
int ask[MAXN] ;
int n , m ;

void init () {
	precntE = 0 ;
	dfs_clock = 0 ;
	clrs ( preH , -1 , n ) ;
}

void preaddedge ( int u , int v , int c ) {
	preE[precntE] = Edge ( v , c , preH[u] ) ;
	preH[u] = precntE ++ ;
}

void addedge ( int u , int v , int c ) {
	if ( vis[u] != Time ) {
		vis[u] = Time ;
		H[u] = -1 ;
	}
	E[cntE] = Edge ( v , c , H[u] ) ;
	H[u] = cntE ++ ;
}

void dfs ( int u ) {
	idx[u] = ++ dfs_clock ;
	for ( int i = preH[u] ; ~i ; i = preE[i].n ) {
		int v = preE[i].v ;
		if ( v == f[u][0] ) continue ;
		dep[v] = dep[u] + 1 ;
		f[v][0] = u ;
		minv[v][0] = preE[i].c ;
		rep ( j , 1 , LOG ) {
			f[v][j] = f[f[v][j - 1]][j - 1] ;
			minv[v][j] = min ( minv[v][j - 1] , minv[f[v][j - 1]][j - 1] ) ;
		}
		dfs ( v ) ;
	}
}

bool cmp ( const int& x , const int& y ) {
	return idx[x] < idx[y] ;
}

int get_lca ( int x , int y ) {
	if ( dep[x] < dep[y] ) swap ( x , y ) ;
	rev ( i , LOG - 1 , 0 ) if ( dep[x] - ( 1 << i ) >= dep[y] ) x = f[x][i] ;
	if ( x == y ) return x ;
	rev ( i , LOG - 1 , 0 ) if ( f[x][i] != f[y][i] ) {
		x = f[x][i] ;
		y = f[y][i] ;
	}
	return f[x][0] ;
}

int get_min ( int x , int y ) {
	int res = INF ;
	if ( dep[x] < dep[y] ) swap ( x , y ) ;
	rev ( i , LOG - 1 , 0 ) if ( dep[x] - ( 1 << i ) >= dep[y] ) {
		res = min ( res , minv[x][i] ) ;
		x = f[x][i] ;
	}
	return res ;
}

LL get_ans ( int u , LL dp = 0 ) {
	for ( int i = H[u] ; ~i ; i = E[i].n ) {
		if ( ask[E[i].v] == Time ) dp += E[i].c ;
		else dp += min ( get_ans ( E[i].v ) , ( LL ) E[i].c ) ;
	}
	return dp ;
}

void deal () {
	int cnt ;
	top = 0 ;
	++ Time ;
	cntE = 0 ;
	scanf ( "%d" , &cnt ) ;
	rep ( i , 0 , cnt ) {
		scanf ( "%d" , &tree[i] ) ;
		ask[tree[i]] = Time ;
	}
	sort ( tree , tree + cnt , cmp ) ;
	if ( tree[0] == 1 ) S[++ top] = tree[0] ;
	else S[++ top] = 1 ;
	rep ( i , tree[0] == 1 , cnt ) {
		int t = tree[i] , lca = get_lca ( S[top] , t ) ;
		while ( top && dep[S[top]] > dep[lca] ) {
			if ( dep[S[top - 1]] <= dep[lca] ) {
				int now = S[top --] ;
				addedge ( lca , now , get_min ( now , lca ) ) ;
				break ;
			}
			addedge ( S[top - 1] , S[top] , get_min ( S[top] , S[top - 1] ) ) ;
			-- top ;
		}
		if ( S[top] != lca ) S[++ top] = lca ;
		S[++ top] = t ;
	}
	while ( top ) {
		addedge ( S[top - 1] , S[top] , get_min ( S[top] , S[top - 1] ) ) ;
		-- top ;
	}
	LL dp = get_ans ( 1 ) ;
	printf ( "%lld\n" , dp ) ;
}

void solve () {
	int u , v , c ;
	init () ;
	rep ( i , 1 , n ) {
		scanf ( "%d%d%d" , &u , &v , &c ) ;
		preaddedge ( u , v , c ) ;
		preaddedge ( v , u , c ) ;
	}
	dfs ( 1 ) ;
	scanf ( "%d" , &m ) ;
	rep ( i , 0 , m ) deal () ;
}

int main () {
	Time = 0 ;
	clr ( vis , 0 ) ;
	clr ( ask , 0 ) ;
	while ( ~scanf ( "%d" , &n ) ) solve () ;
	return 0 ;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值