HDU 5886 Tower Defence(2016青岛网络赛 I题,树的直径 + DP)

题目链接  2016 Qingdao Online Problem I

题意  在一棵给定的树上删掉一条边,求剩下两棵树的树的直径中较长那的那个长度的期望,答案乘上$n-1$后输出。

 

先把原来那棵树的直径求出来。显然删掉的边不是这条直径上的边,那么这时答案就是这条直径的长度。

否则就是直径的某个端点到某一个点(要求连通)的距离的最大值。

在整条链上做两次$DP$之后枚举取较大值即可。

 

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)
#define fi		first
#define se		second

typedef long long LL;

const int N = 100010;

vector <pair<int, LL > > v[N];
int T, n, L, R, x, cnt;
int a[N], f[N], father[N];
LL b[N], c[N], s[N], cl[N], cr[N], c1, c2, num, ans = 0;

void dfs1(int x, int fa, LL now){
	if (now > c1){
		c1 = now;
		L = x;
	}

	for (auto node : v[x]){
		int u = node.fi;
		LL w = node.se;
		if (u == fa) continue;
		dfs1(u, x, now + w);
	}
}

void dfs2(int x, int fa, LL now){
	father[x] = fa;
	s[x] = now;
	if (now > c2){
		c2 = now;
		R = x;
	}

	for (auto node : v[x]){
		int u = node.fi;
		LL w = node.se;
		if (u == fa) continue;
		dfs2(u, x, now + w);
	}
}

void dfs3(int w, int x, LL now){
	f[x] = 1;
	c[w] = max(c[w], now);
	for (auto node : v[x]){
		int u = node.fi;
		if (f[u]) continue;
		dfs3(w, u, now + node.se);
	}
}

int main(){

	for (scanf("%d", &T); T--; ){
		scanf("%d", &n);
		rep(i, 0, n + 1) v[i].clear();
		rep(i, 2, n){
			int x, y;
			LL z;
			scanf("%d%d%lld", &x, &y, &z);
			v[x].push_back({y, z});
			v[y].push_back({x, z});
		}

		L = -1; c1 = -1;
		dfs1(1, 0, 0);
		R = -1, c2 = -1;
		memset(father, 0, sizeof father);
		dfs2(L, 0, 0);

		x = R;
		cnt = 0;
		while (true){
			a[++cnt] = R;
			R = father[R];
			if (R == 0) break;
		}

		rep(i, 1, cnt) b[i] = s[a[i]];
		reverse(a + 1, a + cnt + 1);
		reverse(b + 1, b + cnt + 1);
		
		num = b[cnt];
		ans = num * (n - cnt);

		memset(f, 0, sizeof f);
		rep(i, 1, cnt) f[a[i]] = 1;

		rep(i, 1, cnt){
			c[i] = 0;
			dfs3(i, a[i], 0);
		}


		cl[1] = b[1]; rep(i, 2, cnt) cl[i] = max(cl[i - 1], b[i] + c[i]);
		cr[cnt] = 0;  dec(i, cnt - 1, 1) cr[i] = max(cr[i + 1], b[cnt] - b[i] + c[i]);
		rep(i, 1, cnt - 1) ans = ans + max(cl[i], cr[i + 1]);
		printf("%lld\n", ans);
	}

	return 0;
}

 

posted @ 2018-02-24 22:09  cxhscst2  阅读(210)  评论(0编辑  收藏  举报