#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<=4*10^5,0< c <= 10^5\)
Solution
对于这类不定根的树上问题,一般可以采用换根法解决。
对于这道题,很好想到一种暴力的解法,即 \(n^2\) 暴力枚举每一个节点为根的情况,但是因为 \(4\times 10^5\) 的 \(n\) 的规模,这种办法肯定是需要优化一下的。
想一想暴力计算完一个节点为根的情况后,它所储存的信息有哪些可以给下一个节点继续使用。很明显,如果我们第一次 \(\text{DFS}\) 的时候存储了一个 \(d[i]\) 表示以 \(i\) 为根节点的子树中的最大流量,那么在第二次 \(\text{DFS}\) 中完全是可以用原来的 \(d[i]\) 与 \(d[fa_i]\) 直接得出以 \(i\) 为根情况下的最大流量。如果把这一新的信息记作 \(f[i]\) ,那么可以写出它的计算方式: \(f[i]=d[i]+min(d[fa_i]-min(d[i],val[i]),val[i])\) ( \(val[i]\) 表示到 \(i\) 的节点时经过的那条边的长)。根据这些,代码也很好写了。
值得注意的是,第一次的 \(\text{DFS}\) 是从下向上传递信息,而第二次的 \(\text{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;
}