100003. Tree

来源:互联网 发布:云计算都招聘什么岗位 编辑:程序博客网 时间:2024/06/16 00:11

题目大意

给定一棵以1为根n个节点的树,树上每条边有一个覆盖的限制次数di。现在给出树上的m条链,每条链有一个价值ci。现在可以从中选出一些链,在满足覆盖次数的限制下,求最大的价值。
T组数据。

Data Constraint
T1000,m1000,n100000

题解

考虑网络流,对于每一条树边i(u,v),deepu<deepvuv连一条流量为di费用为0的边。
对于每一条链i,uv,deepu<deepvvu连一条流量为1费用为ci的边。
然后跑最大费用循环流(无源汇最大费用流)。


最大费用循环流

先将所有费用>=0的边强制满流,费用记为ans
degi=inioutiin为入流之和,out为出流之和。
对于所有i(degi<0)Si连一条流量为degi费用为0的边。
对于所有i(degi>0)iT连一条流量为degi费用为0的边。
然后从ST跑一遍最小费用流,本质上就是为了保证流量平衡模拟退流过程。
最后的最大费用就是ansmincost


SRC

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#include<vector>using namespace std ;#define N 500000 + 10#define M 10000 + 10typedef 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 ;}

以上.

1 0