Acwing 287.积蓄程度 (树形DP换根)

题目

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

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

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

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

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

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

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

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

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

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

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

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

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

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

节点编号从1开始。

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

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

数据范围
N≤2∗105
输入样例:
1
5
1 2 11
1 4 13
3 4 5
4 5 10
输出样例:
26

思路

这道题目有点像最大流,这题我们采用树形dp进行换根,因为他要求可能的最大水流,那么如果我们以每个点为根暴力显然超时,所以我们只需要刚开始以一个点为根求出每个点往下的最大流,然后从上往下在dfs一遍,进行dp换根。

代码实现

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define MT(x,i) memset(x,i,sizeof(x) )
#define rev(i,start,end) for (int i=0;i<end;i++)
#define inf 0x3f3f3f3f
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
#define MOD 1000000007
#define exp 1e-8
#define N 1000005 
#define fi first 
#define se second
#define pb push_back
typedef long long ll;
typedef pair<int ,int> PII;
ll gcd (ll a,ll b) {return b?gcd (b,a%b):a; }
inline int read() {
    char ch=getchar(); int x=0, f=1;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f = -1;
        ch=getchar();
    } 
    while('0'<=ch&&ch<='9') {
        x=x*10+ch-'0';
        ch=getchar();
    }   return x*f;
}

const int maxn=2e5+5;
vector <PII> G[maxn];
int n;
int ans;
int d[maxn];
int f[maxn];
int deg[maxn];

int dfs_d (int u,int fa) {
      if (deg[u]==1) {
          d[u]=inf;
          return d[u];
      }
      d[u]=0;
      for (auto it:G[u]) {
          int j=it.first;
          if (j==fa) continue;
          d[u]+=min (dfs_d (j,u),it.second);
      }
      return d[u];
}

void dfs_f (int u,int fa) {
   for (auto it:G[u]) {
       int j=it.first;
       if (j==fa) continue;
       if (deg[j]==1) f[j]=min (f[u]-it.second,it.second);
       else {
           f[j]=d[j]+min (f[u]-min (it.second,d[j]),it.second);
           dfs_f (j,u);
       }
   }
}

int main () {
   ios::sync_with_stdio (false);
   int t;
   cin>>t;
   while (t--) {
        scanf ("%d",&n);
        int temp,flag=0;
        rep (i,1,n) G[i].clear ();
        MT (deg,0);
        rep (i,1,n-1) {
           int a,b,c;
           a=read (), b=read (),c=read ();
           G[a].pb (mp (b,c));
           if (!flag) {
               temp=c;
               flag=1;
           }
           G[b].pb (mp (a,c));
           deg[a]++,deg[b]++;
        }
       
       int root=1;
       while (root<=n&&deg[root]==1) root++;
       if (root>n) {
           cout<<temp<<endl;
           continue;
       }

       dfs_d (root,-1);
       f[root]=d[root];
       dfs_f (root,-1);

       ans=0;
       rep (i,1,n) ans=max (ans,f[i]);
       printf ("%d\n",ans);
   }
   return 0;
}

posted @ 2020-08-07 12:22  Luglucky  阅读(135)  评论(0编辑  收藏  举报