【UOJ #105】【APIO2014】Beads and wires

http://uoj.ac/problem/105
好神的dp啊。
确定一个点为根之后,蓝线只能是竖着的,不能横跨兄弟。
枚举每个点为根进行树形dp是\(O(n^2)\)的,\(f(x,0/1)\)表示以\(x\)为根的子树中\(x\)是否作为蓝线终点的最大值。
更科学的做法:\(O(1)\)把根从一个father转移到它的son。
需要维护\(f(father,1)\)的最大和次大(防止son作为最大转移到father),利用father的信息更新\(f(son,0)\)\(f(son,1)\)的最大和次大(这里的换根不是真正把根换到son,只是说换根后son作为根的信息是正确的,不需要修改father的信息)。
时间复杂度\(O(n)\)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 200003;

struct node {int nxt, to, w;} E[N << 1];
int cnt = 0, point[N], f[N][2], fs[N][2];

void ins(int u, int v, int w) {E[++cnt] = (node) {point[u], v, w}; point[u] = cnt;}

int n, son[N], tot, fadis[N];

void dfs(int x, int fa) {
	for (int i = point[x]; i; i = E[i].nxt)
		if (E[i].to != fa) fadis[E[i].to] = E[i].w, dfs(E[i].to, x);
	
	tot = 0;
	for (int i = point[x]; i; i = E[i].nxt)
		if (E[i].to != fa) son[++tot] = E[i].to;
	
	for (int i = 1; i <= tot; ++i)
		f[x][0] += max(f[son[i]][0], f[son[i]][1]);
	
	int mx = -0x7fffffff, mxs = -0x7fffffff, num;
	for (int i = 1; i <= tot; ++i) {
		num = f[son[i]][0] + fadis[son[i]] - max(f[son[i]][0], f[son[i]][1]);
		if (num >= mx) mxs = mx, mx = num;
		else if (num > mxs) mxs = num;
	}
	
	f[x][1] = mx + fadis[x] + f[x][0];
	fs[x][1] = mxs + fadis[x] + f[x][0];
}

void move(int x, int y, int d) {
	int t, fx0 = f[x][0], fx1 = f[x][1], fxs1 = fs[x][1];
	if (fx1 == fx0 - max(f[y][1], f[y][0]) + f[y][0] + fadis[y]) fx1 = fxs1;
	fx0 -= max(f[y][1], f[y][0]);
	fx1 -= max(f[y][1], f[y][0]);
	fx1 += d;
	f[y][0] += max(fx0, fx1);
	f[y][1] += max(fx0, fx1);
	fs[y][1] += max(fx0, fx1);
	f[y][1] -= d; fs[y][1] -= d;
	if ((t = f[y][0] - max(fx0, fx1) + fx0 + d) >= f[y][1])
		fs[y][1] = f[y][1], f[y][1] = t;
	else if (t > fs[y][1]) fs[y][1] = t;
}

int ans = 0;

void dfsmove(int x, int fa) {
	ans = max(ans, f[x][0]);
	for (int i = point[x]; i; i = E[i].nxt) {
		int v = E[i].to;
		if (v == fa) continue;
		move(x, v, E[i].w);
		dfsmove(v, x);
	}
}

int main() {
	scanf("%d", &n);
	int u, v, e;
	for (int i = 1; i < n; ++i) {
		scanf("%d%d%d", &u, &v, &e);
		ins(u, v, e);
		ins(v, u, e);
	}
	
	dfs(1, 0);
	dfsmove(1, 0);
	printf("%d\n", ans);
	
	return 0;
}
posted @ 2017-04-18 15:39  abclzr  阅读(372)  评论(0编辑  收藏  举报