欢迎神犇吊打|

Hanx16Msgr

园龄:2年8个月粉丝:12关注:3

2022-07-14 09:25阅读: 18评论: 0推荐: 0

#P2007. 水流成河

#P2007. 水流成河

题目描述

成都市要大力发展农业恢复天府之国美称,政府决定在SS市试点修建了很多的水渠,整个水渠系统经过了N个地方,一共有N-1条水渠,每个地方可以相互到达。每条水渠修建的宽度不一样,导致水流容量不同。现在水渠修好了,政府还希望在N个点找一个出来修建水库,水库修建好后就可以源源不断的流出水,那些只和一条河流相连的地方都是连接长江的,我们称这样的地方叫汇点。也就是说水库的水最后会流向汇点。 整个水利系统的水都是固定流速流动,每个地方都不存储水,也就是说除了水库和汇点,每个地方流出的水等于流入的水。 在流量不超过河道容量的前提下,求那个地方修建水库,整个系统的流量最大,求出这个最大值。

输入格式

第一行是一个整数N

接下来N-1行,每行3个数字x,y,C,表示x到y有河流,容量C

输出格式

输出这个最大值

样例

输入数据 1
5
1 2 11
1 4 13
3 4 5
4 5 10
输出数据 1
26

数据规模与约定

N<=4105,0<c<=105

Solution

对于这类不定根的树上问题,一般可以采用换根法解决。

对于这道题,很好想到一种暴力的解法,即 n2 暴力枚举每一个节点为根的情况,但是因为 4×105n 的规模,这种办法肯定是需要优化一下的。

想一想暴力计算完一个节点为根的情况后,它所储存的信息有哪些可以给下一个节点继续使用。很明显,如果我们第一次 DFS 的时候存储了一个 d[i] 表示以 i 为根节点的子树中的最大流量,那么在第二次 DFS 中完全是可以用原来的 d[i]d[fai] 直接得出以 i 为根情况下的最大流量。如果把这一新的信息记作 f[i] ,那么可以写出它的计算方式: f[i]=d[i]+min(d[fai]min(d[i],val[i]),val[i])val[i] 表示到 i 的节点时经过的那条边的长)。根据这些,代码也很好写了。

值得注意的是,第一次的 DFS 是从下向上传递信息,而第二次的 DFS 则是从上向下传递信息。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<limits.h>
#include<cmath>
#define mem(a,b) memset(a,b,sizeof(a));
using namespace std;
template<typename T> void read(T &k)
{
 	k=0;
	T flag=1;char b=getchar();
	while (b<'0' || b>'9') {flag=(b=='-')?-1:1;b=getchar();}
	while (b>='0' && b<='9') {k=(k<<3)+(k<<1)+(b^48);b=getchar();}
	k*=flag;
}
const int _SIZE=4e5;
struct EDGE{
	int next,to,len;
}edge[(_SIZE<<1)+5];
int tot,head[_SIZE+5],inDe[_SIZE+5];
void AddEdge(int x,int y,int v)
{
	++tot;
	edge[tot].next=head[x];
	edge[tot].to=y;
	edge[tot].len=v;
	inDe[y]++;
	head[x]=tot;
}
int n;
int d[_SIZE+5],f[_SIZE+5],val[_SIZE+5];
void dfs1(int x,int fa)
{
	for (int i=head[x];i;i=edge[i].next)
	{
		int twd=edge[i].to;
		if (twd==fa) continue;
		val[twd]=edge[i].len;
		dfs1(twd,x);
		//printf("%d %d %d\n",twd,d[twd],val[twd]);
		if (inDe[twd]==1) d[x]+=val[twd];
		else d[x]+=min(d[twd],val[twd]);
	}
}
void dfs2(int x,int fa)
{
	for (int i=head[x];i;i=edge[i].next)
	{
		int twd=edge[i].to;
		if (twd==fa) continue;
		if (inDe[twd]==1) f[twd]=d[twd]+edge[i].len;
		else f[twd]=d[twd]+min(f[x]-min(d[twd],edge[i].len),edge[i].len);
		dfs2(twd,x);
	}
}
int main()
{
	read(n);
	for (int i=1;i<n;i++)
	{
		int a,b,v;
		read(a),read(b),read(v);
		AddEdge(a,b,v);AddEdge(b,a,v);
	}
	dfs1(1,0);
	f[1]=d[1];
	dfs2(1,0);
	int ans=-1;
	for (int i=1;i<=n;i++)
		ans=max(ans,f[i]);
	printf("%d\n",ans);
	return 0;
}

posted @   Hanx16Msgr  阅读(18)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起