Poj·Accumulation Degree

初见安~这里是传送门:Poj P3585

Description

Trees are an important component of the natural landscape because of their prevention of erosion and the provision of a specific ather-sheltered ecosystem in and under their foliage. Trees have also been found to play an important role in producing oxygen and reducing carbon dioxide in the atmosphere, as well as moderating ground temperatures. They are also significant elements in landscaping and agriculture, both for their aesthetic appeal and their orchard crops (such as apples). Wood from trees is a common building material.

Trees also play an intimate role in many of the world's mythologies. Many scholars are interested in finding peculiar properties about trees, such as the center of a tree, tree counting, tree coloring. A(x) is one of such properties.

A(x) (accumulation degree of node x) is defined as follows:

 

  1. Each edge of the tree has an positive capacity.
  2. The nodes with degree of one in the tree are named terminals.
  3. The flow of each edge can't exceed its capacity.
  4. A(x) is the maximal flow that node x can flow to other terminal nodes.

Since it may be hard to understand the definition, an example is showed below:

 

A(1)=11+5+8=24
Details:1->211
 1->4->35
 1->4->58(since 1->4 has capacity of 13)
A(2)=5+6=11
Details:2->1->4->35
 2->1->4->56
A(3)=5
Details:3->4->55
A(4)=11+5+10=26
Details:4->1->211
 4->35
 4->510
A(5)=10
Details:5->4->1->210

The accumulation degree of a tree is the maximal accumulation degree among its nodes. Here your task is to find the accumulation degree of the given trees.

有一个树形的水系,由 N-1 条河道和 N 个交叉点组成。我们可以把交叉点看作树中的节点,编号为1~N,河道则
看作树中的无向边。每条河道都有一个容量,连接 x 与 y 的河道的容量记为 c(x,y)。河道中单位时间流过的水
量不能超过河道的容量。有一个节点是整个水系的发源地,可以源源不断地流出水,我们称之为源点。除了源点之
外,树中所有度数为1的节点都是入海口,可以吸收无限多的水,我们称之为汇点。也就是说,水系中的水从源点
出发,沿着每条河道,最终流向各个汇点。在整个水系稳定时,每条河道中的水都以单位时间固定的水量流向固定
的方向。除源点和汇点之外,其余各点不贮存水,也就是流入该点的河道水量之和等于从该点流出的河道水量之和
。整个水系的流量就定义为源点单位时间发出的水量。在流量不超过河道容量的前提下,求哪个点作为源点时,整
个水系的流量最大,输出这个最大值。N≤2*10^5

Input

The first line of the input is an integer T which indicates the number of test cases. The first line of each test case is a positive integer n. Each of the following n - 1 lines contains three integers xyz separated by spaces, representing there is an edge between node x and node y, and the capacity of the edge is z. Nodes are numbered from 1 to n.
All the elements are nonnegative integers no more than 200000. You may assume that the test data are all tree metrics.

Output

For each test case, output the result on a single line. 
 

Sample Input

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

Sample Output

26

Sol

看这毒瘤的范围就知道一定不能用nlogn以上的做法。事实证明我们只能用到O(n)的做法。

首先题意很好理解——从选择的源点流出去的水怎么都不会超过任何一条河道的最大容量

既然是让我们求根,那么很明显我们就要用到换根法来解决——这就和洛谷P2986 伟大的奶牛聚集 Great Cow Gather几乎一样了——

因为是无根树,所以为了方便处理,我们以点1为根进行预处理,而后枚举以每个点为根的情况,得到最优解。怎么预处理?

就拿样例来说——【其实题目解释的很清楚了QwQ】

如果我们以点4为根,那么需要考虑的就是:1、4->1->2,分到点1的水不能超过11,往1分的水不能超过13,所以分11的水;2、4->3,不能超过5;3、4->5,不能超过10,所以加起来就是26,也就是最优解。

所以按照换根法的套路,我们需要对于每个点,考虑其子树的部分和其非子树的部分。这里我minn[u][1]表示对于以u为根节点【不是源点!!】的子树,流到点u的最大流量,minn[u][0]表示非点u的子树部分的水流过来的最大流量

对于minn[u][1]我们很好处理——就是子树返回的每一个最小值和该边权取最小。设当前节点为u,子节点为v,则:

minn[u][1] += min(minn[v][1], e[i].w)

但是要特判一下当v为叶子节点的情况,因为叶子没有儿子所以minn[v][1]的值会是0,导致求出来的所有minn[u][1]都是0;所以对于v为叶子的情况,我们直接:

minn[u][1] += e[i].w。或者说到了v的那一层将其赋为极大值,最后累加答案的时候还原回去。

再者就是minn[u][0]。同理,我们考虑的minn[u][0]不仅仅是u的祖先们,还有u的同辈子树,就像minn[2][0],我们考虑的刚好是2以外的所有节点。而因为是从上方过来,每个节点的父亲唯一,所以我们更新的顺序首先应该是minn[v][0],从v流到其他所有节点的话我们需要考虑的就是:其他子树的贡献加上u的祖先的贡献与这条河道取min。也就是:

minn[v][0] = min(minn[u][1] - min(minn[v][1], e[i].w) + minn[u][0], e[i].w)

其他子树的贡献我们用汇集到点u的总贡献减去v子树的贡献得到。

但是这里也有一个类似于关于叶子节点的问题——如果你的父亲上面没有祖先了,而且又只有你一个孩子呢?大约就是这种情况:

这样的话,其他子树的贡献为0,minn[u][0]也为0,那么取min就又出问题了。所以我们还要特判关于父亲节点的性质,就只能存一下每个点的入度来特判了,顺便也可以解决minn[u][1]的特判问题。【我就是当时考虑漏了这个细节WA了两个点QAQ】

也就是说,我们做两次dfs,预处理出minn[u][1]minn[u][0],再统计最大的minn[u][1] + minn[u][0]即可。

上代码——

#include<bits/stdc++.h>//码风更改中,有点丑陋。
using namespace std;
const int maxn = 2e5 + 10;
int read() {
	int x = 0, ch = getchar();
	while(!isdigit(ch)) ch = getchar();
	while(isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar();
	return x;
}

struct edge {
	int to, w, nxt;
	edge() {}
	edge(int t, int ww, int nn) {to = t, w = ww, nxt = nn;}
}e[maxn << 1];

int head[maxn], k = 0;
void add(int u, int v, int w) {
	e[k] = edge(v, w, head[u]);
	head[u] = k++;
}

int fa[maxn], minn[maxn][2], deg[maxn];//0 up 1 down
void dfs1(int u) {
	register int v;
	for(int i = head[u]; ~i; i = e[i].nxt) {
		v = e[i].to;
		if(v == fa[u]) continue;
		fa[v] = u;//fa和vis的效果一样的
		dfs1(v);
		if(deg[v] == 1) minn[u][1] += e[i].w;//特判1
		else minn[u][1] += min(minn[v][1], e[i].w);//因为是统计各个子树支流,所以要累加
	}
}

void dfs2(int u) {
	register int v;
	for(int i = head[u]; ~i; i = e[i].nxt) {
		v = e[i].to;
		if(v == fa[u]) continue;
		if(deg[u] == 1) minn[v][0] = e[i].w;//特判2
		else minn[v][0] = min(minn[u][1] - min(minn[v][1], e[i].w) + minn[u][0], e[i].w);
		dfs2(v);
	}
}

int t, n, tmp, ans;
signed main() {
	freopen("in.txt", "r", stdin);//不用在意这一句
	t = read();
	register int u, v, w;
	while(t--)
	{
		memset(head, -1, sizeof head); k = 0;
		memset(minn, 0, sizeof minn);
		memset(deg, 0, sizeof deg);//记得要初始化
		ans = 0;
		n = read();
		for(int i = 1; i < n; i++) {
			u = read(), v = read(), w = read();
			add(u, v, w), add(v, u, w); deg[u]++, deg[v]++;//记录度
		}
		
		dfs1(1);
		dfs2(1);
		for(int i = 1; i <= n; i++) {
			ans = max(ans, minn[i][0] + minn[i][1]);
		}
		printf("%d\n", ans);
	}
}

总体来说是很简单的一个换根法树形dp的题!!!【第二次遇见了我竟然还是没有AC……】

迎评:)
——End——

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值