积累程度 poj3585

10 篇文章 0 订阅

有一个树形的水系,由 N-1 条河道和 N 个交叉点组成。

我们可以把交叉点看作树中的节点,编号为 1~N,河道则看作树中的无向边。

每条河道都有一个容量,连接 x 与 y 的河道的容量记为 c(x,y)。

河道中单位时间流过的水量不能超过河道的容量。

有一个节点是整个水系的发源地,可以源源不断地流出水,我们称之为源点。

除了源点之外,树中所有度数为 1 的节点都是入海口,可以吸收无限多的水,我们称之为汇点。

也就是说,水系中的水从源点出发,沿着每条河道,最终流向各个汇点。

在整个水系稳定时,每条河道中的水都以单位时间固定的水量流向固定的方向。

除源点和汇点之外,其余各点不贮存水,也就是流入该点的河道水量之和等于从该点流出的河道水量之和。

整个水系的流量就定义为源点单位时间发出的水量。

在流量不超过河道容量的前提下,求哪个点作为源点时,整个水系的流量最大,输出这个最大值。

输入格式

输入第一行包含整数T,表示共有T组测试数据。

每组测试数据,第一行包含整数N。

接下来N-1行,每行包含三个整数x,y,z,表示x,y之间存在河道,且河道容量为z。

节点编号从1开始。

输出格式

每组数据输出一个结果,每个结果占一行。

数据保证结果不超过231−1231−1。

数据范围

N≤2∗105N≤2∗105

输入样例:

1
5
1 2 11
1 4 13
3 4 5
4 5 10

输出样例:

26

最重要的数组要开大我开3e+测试的时候超时卡了一上午没看出来(忘了考虑存的是无向图),我想应该是数组模拟的邻接表在存数据的时候计数变量超了,如果是用结构体的话应该就可以开2e+。 这就是 二次扫描+换根法的典型题。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
typedef long long ll;

using namespace std;
const int N=700100;
ll Head[N],edge[N],Next[N],dp[N],d[N],tot=0,point[N],du[N];
int n;
bool v[N];
inline void adds(int x,int y,int z)
{
    tot++;
    point[tot]=y;
    Next[tot]=Head[x];
    Head[x]=tot;
    edge[tot]=z;
}

void dfsd(int x)
{
    v[x]=1;
    d[x]=0;
    for(int i=Head[x]; i; i=Next[i])
    {
        int y=point[i];
        if(v[y])
            continue;

        dfsd(y);
        if(du[y]==1)
            d[x]+=edge[i];
        else
            d[x]+=min(edge[i],d[y]);
    }
}

void dfs(int x)
{
    v[x]=1;
    for(int i=Head[x]; i; i=Next[i])
    {
        int y=point[i];
        if(v[y])
            continue;

        if(du[x]==1)
            dp[y]=edge[i]+d[y];
        else
        {
            dp[y]=d[y]+min(dp[x]-min(d[y],edge[i]),edge[i]);
        }
        dfs(y);
    }
}

int main()
{
    int jb;
    scanf("%d",&jb);
    while(jb--)
    {
        tot=0;
        memset(Next,0,sizeof(Next));
        memset(Head,0,sizeof(Head));
        
        memset(du,0,sizeof(du));
        cin>>n;
        for(int i=1; i<n; i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            adds(x,y,z);
            adds(y,x,z);
            du[x]++,du[y]++;
        }
        int root=1;
        memset(v,0,sizeof(v));
        dfsd(root);
        dp[root]=d[root];
        memset(v,0,sizeof(v));

        dfs(root);

        ll ans=-1;

        for(int i=1; i<=n; i++)
        {
            ans=max(ans,dp[i]);
            //cout<<dp[i]<<' '<<d[i]<<endl;

        }
        printf("%lld\n",ans);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值