题目大意
给定一棵以1为根
n
个节点的树,树上每条边有一个覆盖的限制次数
T
组数据。
Data Constraint
题解
考虑网络流,对于每一条树边
i
,
对于每一条链
然后跑最大费用循环流(无源汇最大费用流)。
最大费用循环流
先将所有费用>=0的边强制满流,费用记为
ans
记
degi=ini−outi
,
in
为入流之和,
out
为出流之和。
对于所有
i(degi<0)
,
S
向
对于所有
然后从
最后的最大费用就是
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std ;
#define N 500000 + 10
#define M 10000 + 10
typedef long long ll ;
struct Path {
int u , v , c ;
} P[N] ;
struct Edge {
int u , v , d ;
} E[N] ;
vector < int > G[N] ;
int Node[10*N] , Next[10*N] , C[10*N] , Cost[10*N] , Head[M] , tot ;
int D[10*N] , Pre[N] , vis[N] ;
ll Dist[M] ;
int Deep[N] , fa[N] , Deg[M] ;
int Case , n , m ;
int S , T ;
ll ans ;
bool cmp( Path a , Path b ) { return a.c > b.c || ( a.c == b.c && Deep[a.u] - Deep[a.v] < Deep[b.u] - Deep[b.v] ) ; }
void DFS( int x , int F ) {
fa[x] = F ;
for (int p = 0 ; p < G[x].size() ; p ++ ) {
if ( G[x][p] == F ) continue ;
Deep[G[x][p]] = Deep[x] + 1 ;
DFS( G[x][p] , x ) ;
}
}
void link( int u , int v , int w , int cost ) {
Node[++tot] = v , Next[tot] = Head[u] , C[tot] = w , Cost[tot] = cost , Head[u] = tot ;
Node[++tot] = u , Next[tot] = Head[v] , C[tot] = 0 , Cost[tot] = -cost , Head[v] = tot ;
}
bool SPFA( int st ) {
memset( Dist , 63 , sizeof(Dist) ) ;
int i = 0 , j = 1 ;
D[1] = st ;
vis[st] = 1 ;
Dist[st] = 0 ;
while ( i < j ) {
i ++ ;
int now = D[i] ;
for (int p = Head[now] ; p ; p = Next[p] ) {
if ( !C[p] ) continue ;
if ( Dist[now] + Cost[p] < Dist[Node[p]] ) {
Dist[Node[p]] = Dist[now] + Cost[p] ;
Pre[Node[p]] = p ;
if ( !vis[Node[p]] ) {
vis[Node[p]] = 1 ;
D[++j] = Node[p] ;
if ( Dist[D[j]] < Dist[D[i+1]] ) swap( D[i+1] , D[j] ) ;
}
}
}
vis[now] = 0 ;
}
return Dist[T] < Dist[T+1] ;
}
ll MinCost() {
ll ret = 0 ;
while ( SPFA(S) ) {
int Minv = 0x7FFFFFFF ;
for (int x = T ; x != S ; x = Node[Pre[x]^1] ) Minv = min( Minv , C[Pre[x]] ) ;
ret += (ll)Minv * Dist[T] ;
for (int x = T ; x != S ; x = Node[Pre[x]^1] ) {
C[Pre[x]] -= Minv ;
C[Pre[x]^1] += Minv ;
}
}
return ret ;
}
int main() {
freopen( "tree.in" , "r" , stdin ) ;
freopen( "tree.out" , "w" , stdout ) ;
scanf( "%d" , &Case ) ;
while ( Case -- ) {
ans = 0 ;
tot = 1 ;
memset( Deg , 0 , sizeof(Deg) ) ;
memset( Head , 0 , sizeof(Head) ) ;
scanf( "%d%d" , &n , &m ) ;
S = 0 , T = n + 1 ;
for (int i = 1 ; i <= n ; i ++ ) G[i].clear() ;
for (int i = 1 ; i < n ; i ++ ) {
scanf( "%d%d%d" , &E[i].u , &E[i].v , &E[i].d ) ;
G[E[i].u].push_back( E[i].v ) ;
G[E[i].v].push_back( E[i].u ) ;
}
Deep[1] = 1 ;
DFS( 1 , 0 ) ;
for (int i = 1 ; i < n ; i ++ ) {
if ( Deep[E[i].u] > Deep[E[i].v] ) swap( E[i].u , E[i].v ) ;
link( E[i].u , E[i].v , E[i].d , 0 ) ;
Deg[E[i].u] -= E[i].d , Deg[E[i].v] += E[i].d ;
}
for (int i = 1 ; i <= m ; i ++ ) {
scanf( "%d%d%d" , &P[i].u , &P[i].v , &P[i].c ) ;
if ( Deep[P[i].u] < Deep[P[i].v] ) swap( P[i].u , P[i].v ) ;
ans += P[i].c ;
Deg[P[i].v] ++ , Deg[P[i].u] -- ;
link( P[i].u , P[i].v , 1 , P[i].c ) ;
}
for (int i = 1 ; i <= n ; i ++ ) {
if ( Deg[i] < 0 ) link( S , i , -Deg[i] , 0 ) ;
else link( i , T , Deg[i] , 0 ) ;
}
ll tmp = MinCost() ;
printf( "%lld\n" , ans - tmp ) ;
}
return 0 ;
}
以上.