100003. Tree
来源:互联网 发布:云计算都招聘什么岗位 编辑:程序博客网 时间:2024/06/16 00:11
题目大意
给定一棵以1为根
Data Constraint
题解
考虑网络流,对于每一条树边
对于每一条链
然后跑最大费用循环流(无源汇最大费用流)。
最大费用循环流
先将所有费用>=0的边强制满流,费用记为
记
对于所有
对于所有
然后从
最后的最大费用就是
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
- 100003. Tree
- Tree
- tree
- tree
- TREE
- Tree
- Tree
- tree
- tree
- tree
- tree
- tree
- tree
- Tree
- Tree
- tree
- TREE
- tree
- MyBatis动态sql详解(一)
- 设计模式原则—开闭原则(OCP)
- 读书笔记之适配器模式
- 二叉树的后序遍历--非递归实现
- java Stringbuffer的使用
- 100003. Tree
- CodeForces
- C#中DllImport用法汇总
- hdu2852 KiKi's K-Number 线段树
- LeetCode#91. Decode Ways
- Week Training: 452 Minimum Number of Arrows to Burst Balloons
- 螺旋矩阵 II
- 客户端显示2008连接上却实2005数据库
- prophet:时间序列预测模型原理