码迷,mamicode.com
首页 > 其他好文 > 详细

「UVA 12161」Ironman Race in Treeland

时间:2020-05-08 22:55:56      阅读:58      评论:0      收藏:0      [点我收藏+]

标签:ack   http   i++   pac   roo   https   tree   class   std   

Description

给定一个 \(n\) 个结点的树,每条边有两个属性:长度 \(L\) 和花费 \(D\)

现给定最大花费值 \(m\),求出花费总和不超过 \(m\) 的路径中长度的最大值。

Hint

\(1\le n\le 3\times 10^4, 1\le m\le 10^8, 1\le L,D\le 10^3\)

Solution

这种树上路径的问题,不难想到 点分治

难点在于如何得到经过根的最优的路径。

我们一个个子结点来看,假如现在处理到子结点为 \(x_k\),如下图:

技术图片

那么 \(x_1, x_2,\cdots,x_{k-1}\) 的子树已经处理完了。

现在枚举子树 \(x_k\) 中的所有一个端点为根的路径,当枚举到一条路径的信息为 \((D^\prime, L^\prime)\),我们就在子树 \(x_1,x_2,\cdots, x_{k-1}\) 中的所有路径信息中匹配——找到其中 \(D\)\(\le m - D^\prime\) 的所有路径中 \(L\) 值的最大值。

这样的话,处理方式就非常多了,比较好的做法可以平衡树,但这里介绍一种虽然效率稍劣但十分简单好理解且细节极少的 动态开点线段树 做法。

回到原来那个匹配的问题:我们把前 \(k-1\) 个子树的路径信息存入一个动态开点线段树中,对 \(D\) 值域(位置)开线段树,结点维护 \(L\) 的最大值。那么就可以求出位置 \([0,D^\prime -1]\) 的最大值,然后子树 \(x_k\) 处理完后,在把其中的路径信息以 \(D\) 为位置,\(L\) 为值,做 单点最值操作,即 \(\text{val}_D \leftarrow \max(\text{val}_D, L)\)。还有就是记得及时清空。

这样的算法复杂度是多少呢?动态开点线段树的空间一次修改是最大多开 \(\log U\)\(U\) 为值域,下同)个结点,所以空间复杂度为 \(O(n\log U)\)

由于深度也是最大 \(\log U\) 层,所以时间复杂度为 \(O(n\log n \log U)\)

Code

跑了 380ms,效率还是挺可观的。

#include <algorithm>
#include <cstdio>
#include <utility>
#include <vector>

using namespace std;
const int N = 3e4 + 5;

namespace dysgt {
	const int LogU = 27;
	const int S = N * LogU;
	const int Lim = 1e8;
	int lc[S], rc[S];
	int maxv[S];
	int total = 0;
	int root = 0;
	
	inline void destroy(int x) {
		lc[x] = rc[x] = maxv[x] = 0;
	}
	inline void modify(int p, int v) {
		int l = 0, r = Lim;
		if (!root) root = ++total;
		for (register int x = root; l != r; ) {
			maxv[x] = max(maxv[x], v);
			int mid = (l + r) >> 1;
			if (p <= mid) x = !lc[x] ? (lc[x] = ++total) : lc[x], r = mid;
			else x = !rc[x] ? (rc[x] = ++total) : rc[x], l = mid + 1;
		}
	}
	int getMax(int L, int R, int l = 0, int r = Lim, int x = root) {
		if (!x) return 0;
		if (L <= l && r <= R) return maxv[x];
		int ret = 0, mid = (l + r) >> 1;
		if (l <= mid) ret = max(ret, getMax(L, R, l, mid, lc[x]));
		if (r > mid) ret = max(ret, getMax(L, R, mid + 1, r, rc[x]));
		return ret;
	}
	void _S_clr(int x) {
		if (!x) return;
		_S_clr(lc[x]), _S_clr(rc[x]);
		destroy(x);
	}
	inline void clear() {
		_S_clr(root);
		root = total = 0;
	}
}

int n, m;
struct edge { int to, len, dam; };
vector<edge> G[N];

bool centr[N];
int maxp[N], size[N];
int root;
int getSize(int x, int f) {
	size[x] = 1;
	for (auto y : G[x])
		if (y.to != f && !centr[y.to])
			size[x] += getSize(y.to, x);
	return size[x];
}
void getCentr(int x, int f, int t) {
	maxp[x] = 0;
	for (auto y : G[x]) {
		if (y.to == f || centr[y.to]) continue;
		getCentr(y.to, x, t);
		maxp[x] = max(maxp[x], size[y.to]);
	}
	maxp[x] = max(maxp[x], t - size[x]);
	if (maxp[x] < maxp[root]) root = x;
}

pair<int, int> path[N];
int tot;
void getPaths(int x, int f, int l, int d) {
	if (d > m) return;
	path[++tot] = {d, l};
	for (auto y : G[x])
		if (y.to != f && !centr[y.to])
			getPaths(y.to, x, l + y.len, d + y.dam);
}

int ans;
void solve(int x) {
	getSize(x, 0);
	maxp[root = 0] = N;
	getCentr(x, 0, size[x]);
	int s = root;
	centr[s] = true;
	
	for (auto y : G[s])
		if (!centr[y.to])
			solve(y.to);
	
	dysgt::clear(), dysgt::modify(0, 0);
	for (auto y : G[s]) {
		if (centr[y.to]) continue;
		tot = 0, getPaths(y.to, x, y.len, y.dam);
		for (register int i = 1; i <= tot; i++)
			ans = max(ans, dysgt::getMax(0, m - path[i].first) + path[i].second);
		for (register int i = 1; i <= tot; i++)
			dysgt::modify(path[i].first, path[i].second);
	}
	
	centr[s] = false;
}

signed main() {
	int T; scanf("%d", &T);
	for (register int tc = 1; tc <= T; tc++) {
		scanf("%d%d", &n, &m);
		for (register int i = 1; i <= n; i++) {
			G[i].clear();
			maxp[i] = size[i] = 0;
			centr[i] = false;
		}
		
		for (register int i = 1; i < n; i++) {
			int u, v, l, d;
			scanf("%d%d%d%d", &u, &v, &d, &l);
			G[u].push_back({v, l, d});
			G[v].push_back({u, l, d});
		}
		
		ans = 0, solve(1);
		printf("Case %d: %d\n", tc, ans);
	}
	return 0;
}

「UVA 12161」Ironman Race in Treeland

标签:ack   http   i++   pac   roo   https   tree   class   std   

原文地址:https://www.cnblogs.com/-Wallace-/p/12853448.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!